From ffcab7c0aedd65518d3ff31db7a1ad5def0cf226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Tue, 24 May 2016 11:14:11 +0200 Subject: [PATCH] bus: Fix timeout restarts The code counting pending fds relied on restart of timeouts when they are enabled. This patch adds function that ensures that such enabled timeouts have their timekeeping data reset (and not only when timeout is registered into event loop processing). When timeouts weren't reset, they'd fire at rather random and mainly incorrect moments leading to interruption of connections of dbus-daemon. diff --git a/bus/connection.c b/bus/connection.c index 67793ba..897a945 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -655,7 +655,7 @@ check_pending_fds_cb (DBusConnection *connection) { _dbus_timeout_set_interval (d->pending_unix_fds_timeout, bus_context_get_pending_fd_timeout (d->connections->context)); - _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, TRUE); + _dbus_timeout_set_reenabled (d->pending_unix_fds_timeout, TRUE); } if (n_pending_unix_fds_old > 0 && n_pending_unix_fds_new == 0) diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index fe4d04e..e46bff8 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -488,6 +488,10 @@ DBUS_EXPORT dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout); DBUS_EXPORT dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout); +DBUS_EXPORT +dbus_bool_t dbus_timeout_needs_restart(DBusTimeout *timeout); +DBUS_EXPORT +void dbus_timeout_restarted (DBusTimeout *timeout); /** @} */ diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c index f6736fe..fecc81d 100644 --- a/dbus/dbus-mainloop.c +++ b/dbus/dbus-mainloop.c @@ -606,6 +606,14 @@ _dbus_loop_iterate (DBusLoop *loop, if (dbus_timeout_get_enabled (tcb->timeout)) { + if (dbus_timeout_needs_restart (tcb->timeout)) + { + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + dbus_timeout_restarted (tcb->timeout); + } + + int msecs_remaining; check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index a1d6ce5..ac1ed47 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -49,6 +49,7 @@ struct DBusTimeout void *data; /**< Application data. */ DBusFreeFunction free_data_function; /**< Free the application data. */ unsigned int enabled : 1; /**< True if timeout is active. */ + unsigned int needs_restart : 1; /**< Flag that timeout should be restarted after re-enabling. */ }; /** @@ -79,6 +80,7 @@ _dbus_timeout_new (int interval, timeout->free_handler_data_function = free_data_function; timeout->enabled = TRUE; + timeout->needs_restart = FALSE; return timeout; } @@ -156,6 +158,24 @@ _dbus_timeout_set_enabled (DBusTimeout *timeout, timeout->enabled = enabled != FALSE; } +/** + * See _dbus_timeout_set_enabled() for detailed operation. + * This variant marks the timer for restart (since _dbus_timeout_set_enabled + * won't cause timeout to be restarted). + * + * @param timeout the timeout + * @param enabled #TRUE if timeout should be enabled. + */ +void +_dbus_timeout_set_reenabled (DBusTimeout *timeout, + dbus_bool_t enabled) +{ + timeout->enabled = enabled != FALSE; + if (timeout->enabled) { + timeout->needs_restart = TRUE; + } +} + /** * @typedef DBusTimeoutList @@ -488,4 +508,29 @@ dbus_timeout_get_enabled (DBusTimeout *timeout) return timeout->enabled; } +/** + * Returns whether a timeout needs restart time counting in the event loop. + * + * @param timeout the DBusTimeout object + * @returns #TRUE if restart is needed + */ +dbus_bool_t +dbus_timeout_needs_restart (DBusTimeout *timeout) +{ + return timeout->needs_restart; +} + +/** + * Mark timeout as restarted (setting timestamps is responsibility of the event + * loop). + * + * @param timeout the DBusTimeout object + */ +void +dbus_timeout_restarted (DBusTimeout *timeout) +{ + timeout->needs_restart = FALSE; +} + + /** @} end public API docs */ diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h index c652bb7..bd9de70 100644 --- a/dbus/dbus-timeout.h +++ b/dbus/dbus-timeout.h @@ -54,6 +54,9 @@ void _dbus_timeout_set_interval (DBusTimeout *timeout, DBUS_PRIVATE_EXPORT void _dbus_timeout_set_enabled (DBusTimeout *timeout, dbus_bool_t enabled); +DBUS_PRIVATE_EXPORT +void _dbus_timeout_set_reenabled(DBusTimeout *timeout, + dbus_bool_t enabled); DBusTimeoutList *_dbus_timeout_list_new (void); void _dbus_timeout_list_free (DBusTimeoutList *timeout_list);