From e8fe0dad81378920c6c537013f8759dfe9144bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 12 Feb 2015 01:53:03 +0100 Subject: Import optimized event loop from ponymap --- zyklonb.c | 101 +++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 38 deletions(-) (limited to 'zyklonb.c') diff --git a/zyklonb.c b/zyklonb.c index f9624b9..e3289d9 100644 --- a/zyklonb.c +++ b/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) -- cgit v1.2.3