Import optimized event loop from ponymap
This commit is contained in:
101
zyklonb.c
101
zyklonb.c
@@ -73,6 +73,9 @@ struct plugin_data
|
||||
int read_fd; ///< The read end of the comm. pipe
|
||||
int write_fd; ///< The write end of the comm. pipe
|
||||
|
||||
struct poller_fd read_event; ///< Read FD event
|
||||
struct poller_fd write_event; ///< Write FD event
|
||||
|
||||
struct str read_buffer; ///< Unprocessed input
|
||||
struct str write_buffer; ///< Output yet to be sent out
|
||||
};
|
||||
@@ -118,8 +121,14 @@ struct bot_context
|
||||
|
||||
int irc_fd; ///< Socket FD of the server
|
||||
struct str read_buffer; ///< Input yet to be processed
|
||||
struct poller_fd irc_event; ///< IRC FD event
|
||||
bool irc_ready; ///< Whether we may send messages now
|
||||
|
||||
struct poller_fd signal_event; ///< Signal FD event
|
||||
struct poller_timer ping_tmr; ///< We should send a ping
|
||||
struct poller_timer timeout_tmr; ///< Connection seems to be dead
|
||||
struct poller_timer reconnect_tmr; ///< We should reconnect now
|
||||
|
||||
SSL_CTX *ssl_ctx; ///< SSL context
|
||||
SSL *ssl; ///< SSL connection
|
||||
|
||||
@@ -131,6 +140,10 @@ struct bot_context
|
||||
bool polling; ///< The event loop is running
|
||||
};
|
||||
|
||||
static void on_irc_ping_timeout (void *user_data);
|
||||
static void on_irc_timeout (void *user_data);
|
||||
static void on_irc_reconnect_timeout (void *user_data);
|
||||
|
||||
static void
|
||||
bot_context_init (struct bot_context *self)
|
||||
{
|
||||
@@ -152,6 +165,18 @@ bot_context_init (struct bot_context *self)
|
||||
poller_init (&self->poller);
|
||||
self->quitting = false;
|
||||
self->polling = false;
|
||||
|
||||
poller_timer_init (&self->timeout_tmr, &self->poller);
|
||||
self->timeout_tmr.dispatcher = on_irc_timeout;
|
||||
self->timeout_tmr.user_data = self;
|
||||
|
||||
poller_timer_init (&self->ping_tmr, &self->poller);
|
||||
self->ping_tmr.dispatcher = on_irc_ping_timeout;
|
||||
self->ping_tmr.user_data = self;
|
||||
|
||||
poller_timer_init (&self->reconnect_tmr, &self->poller);
|
||||
self->reconnect_tmr.dispatcher = on_irc_reconnect_timeout;
|
||||
self->reconnect_tmr.user_data = self;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -172,7 +197,10 @@ bot_context_free (struct bot_context *self)
|
||||
}
|
||||
|
||||
if (self->irc_fd != -1)
|
||||
{
|
||||
xclose (self->irc_fd);
|
||||
poller_fd_reset (&self->irc_event);
|
||||
}
|
||||
if (self->ssl)
|
||||
SSL_free (self->ssl);
|
||||
if (self->ssl_ctx)
|
||||
@@ -1060,10 +1088,7 @@ plugin_zombify (struct plugin_data *plugin)
|
||||
// empty before closing it... and then on EOF check if `pid == -1' and
|
||||
// only then dispose of it (it'd be best to simulate that both of these
|
||||
// cases may happen).
|
||||
ssize_t poller_idx =
|
||||
poller_find_by_fd (&plugin->ctx->poller, plugin->write_fd);
|
||||
if (poller_idx != -1)
|
||||
poller_remove_at_index (&plugin->ctx->poller, poller_idx);
|
||||
poller_fd_reset (&plugin->write_event);
|
||||
|
||||
// TODO: try to flush the write buffer (non-blocking)?
|
||||
|
||||
@@ -1083,7 +1108,6 @@ plugin_zombify (struct plugin_data *plugin)
|
||||
static void
|
||||
on_plugin_writable (const struct pollfd *fd, struct plugin_data *plugin)
|
||||
{
|
||||
struct bot_context *ctx = plugin->ctx;
|
||||
struct str *buf = &plugin->write_buffer;
|
||||
size_t written_total = 0;
|
||||
|
||||
@@ -1124,12 +1148,8 @@ on_plugin_writable (const struct pollfd *fd, struct plugin_data *plugin)
|
||||
str_remove_slice (buf, 0, written_total);
|
||||
|
||||
if (buf->len == 0)
|
||||
{
|
||||
// Everything has been written, there's no need to end up in here again
|
||||
ssize_t index = poller_find_by_fd (&ctx->poller, fd->fd);
|
||||
if (index != -1)
|
||||
poller_remove_at_index (&ctx->poller, index);
|
||||
}
|
||||
poller_fd_reset (&plugin->write_event);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1148,9 +1168,7 @@ plugin_queue_write (struct plugin_data *plugin)
|
||||
plugin_zombify (plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
poller_set (&plugin->ctx->poller, plugin->write_fd, POLLOUT,
|
||||
(poller_dispatcher_fn) on_plugin_writable, plugin);
|
||||
poller_fd_set (&plugin->write_event, POLLOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1412,11 +1430,18 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e)
|
||||
plugin->read_fd = stdout_pipe[0];
|
||||
plugin->write_fd = stdin_pipe[1];
|
||||
|
||||
poller_fd_init (&plugin->read_event, &ctx->poller, plugin->read_fd);
|
||||
plugin->read_event.dispatcher = (poller_fd_fn) on_plugin_readable;
|
||||
plugin->read_event.user_data = plugin;
|
||||
|
||||
poller_fd_init (&plugin->write_event, &ctx->poller, plugin->write_fd);
|
||||
plugin->write_event.dispatcher = (poller_fd_fn) on_plugin_writable;
|
||||
plugin->write_event.user_data = plugin;
|
||||
|
||||
LIST_PREPEND (ctx->plugins, plugin);
|
||||
str_map_set (&ctx->plugins_by_name, name, plugin);
|
||||
|
||||
poller_set (&ctx->poller, stdout_pipe[0], POLLIN,
|
||||
(poller_dispatcher_fn) on_plugin_readable, plugin);
|
||||
poller_fd_set (&plugin->read_event, POLLIN);
|
||||
return true;
|
||||
|
||||
fail_3:
|
||||
@@ -1818,14 +1843,13 @@ static void irc_queue_reconnect (struct bot_context *);
|
||||
static void
|
||||
irc_cancel_timers (struct bot_context *ctx)
|
||||
{
|
||||
ssize_t i;
|
||||
struct poller_timers *timers = &ctx->poller.timers;
|
||||
while ((i = poller_timers_find_by_data (timers, ctx)) != -1)
|
||||
poller_timers_remove_at_index (timers, i);
|
||||
poller_timer_reset (&ctx->timeout_tmr);
|
||||
poller_timer_reset (&ctx->ping_tmr);
|
||||
poller_timer_reset (&ctx->reconnect_tmr);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_on_reconnect_timeout (void *user_data)
|
||||
on_irc_reconnect_timeout (void *user_data)
|
||||
{
|
||||
struct bot_context *ctx = user_data;
|
||||
|
||||
@@ -1847,8 +1871,7 @@ irc_queue_reconnect (struct bot_context *ctx)
|
||||
hard_assert (ctx->irc_fd == -1);
|
||||
print_status ("trying to reconnect in %ld seconds...",
|
||||
ctx->reconnect_delay);
|
||||
poller_timers_add (&ctx->poller.timers,
|
||||
irc_on_reconnect_timeout, ctx, ctx->reconnect_delay * 1000);
|
||||
poller_timer_set (&ctx->reconnect_tmr, ctx->reconnect_delay * 1000);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1863,14 +1886,13 @@ on_irc_disconnected (struct bot_context *ctx)
|
||||
ctx->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
ssize_t i = poller_find_by_fd (&ctx->poller, ctx->irc_fd);
|
||||
if (i != -1)
|
||||
poller_remove_at_index (&ctx->poller, i);
|
||||
|
||||
xclose (ctx->irc_fd);
|
||||
ctx->irc_fd = -1;
|
||||
ctx->irc_ready = false;
|
||||
|
||||
ctx->irc_event.closed = true;
|
||||
poller_fd_reset (&ctx->irc_event);
|
||||
|
||||
// TODO: inform plugins about the disconnect event
|
||||
|
||||
// All of our timers have lost their meaning now
|
||||
@@ -1905,10 +1927,8 @@ static void
|
||||
irc_reset_connection_timeouts (struct bot_context *ctx)
|
||||
{
|
||||
irc_cancel_timers (ctx);
|
||||
poller_timers_add (&ctx->poller.timers,
|
||||
on_irc_timeout, ctx, 3 * 60 * 1000);
|
||||
poller_timers_add (&ctx->poller.timers,
|
||||
on_irc_ping_timeout, ctx, (3 * 60 + 30) * 1000);
|
||||
poller_timer_set (&ctx->timeout_tmr, 3 * 60 * 1000);
|
||||
poller_timer_set (&ctx->ping_tmr, (3 * 60 + 30) * 1000);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2026,11 +2046,14 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
||||
}
|
||||
print_status ("connection established");
|
||||
|
||||
poller_fd_init (&ctx->irc_event, &ctx->poller, ctx->irc_fd);
|
||||
ctx->irc_event.dispatcher = (poller_fd_fn) on_irc_readable;
|
||||
ctx->irc_event.user_data = ctx;
|
||||
|
||||
// TODO: in exec try: 1/ set blocking, 2/ setsockopt() SO_LINGER,
|
||||
// (struct linger) { .l_onoff = true; .l_linger = 1 /* 1s should do */; }
|
||||
// 3/ /* O_CLOEXEC */ But only if the QUIT message proves unreliable.
|
||||
poller_set (&ctx->poller, ctx->irc_fd, POLLIN,
|
||||
(poller_dispatcher_fn) on_irc_readable, ctx);
|
||||
poller_fd_set (&ctx->irc_event, POLLIN);
|
||||
irc_reset_connection_timeouts (ctx);
|
||||
|
||||
irc_send (ctx, "NICK %s", nickname);
|
||||
@@ -2134,13 +2157,12 @@ on_signal_pipe_readable (const struct pollfd *fd, struct bot_context *ctx)
|
||||
|
||||
plugin->pid = -1;
|
||||
|
||||
ssize_t poller_idx = poller_find_by_fd (&ctx->poller, plugin->read_fd);
|
||||
if (poller_idx != -1)
|
||||
poller_remove_at_index (&ctx->poller, poller_idx);
|
||||
|
||||
xclose (plugin->read_fd);
|
||||
plugin->read_fd = -1;
|
||||
|
||||
plugin->read_event.closed = true;
|
||||
poller_fd_reset (&plugin->read_event);
|
||||
|
||||
LIST_UNLINK (ctx->plugins, plugin);
|
||||
plugin_data_free (plugin);
|
||||
free (plugin);
|
||||
@@ -2215,8 +2237,11 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
setup_recovery_handler (&ctx);
|
||||
poller_set (&ctx.poller, g_signal_pipe[0], POLLIN,
|
||||
(poller_dispatcher_fn) on_signal_pipe_readable, &ctx);
|
||||
|
||||
poller_fd_init (&ctx.signal_event, &ctx.poller, g_signal_pipe[0]);
|
||||
ctx.signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable;
|
||||
ctx.signal_event.user_data = &ctx;
|
||||
poller_fd_set (&ctx.signal_event, POLLIN);
|
||||
|
||||
plugin_load_all_from_config (&ctx);
|
||||
if (!parse_config (&ctx, &e)
|
||||
|
||||
Reference in New Issue
Block a user