From 3db673bf5f53ee2963e7b21d01062b93630670c5 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 9 Nov 2018 10:39:11 -0500 Subject: [PATCH] account: don't poll more frequently than notification period At the moment, if an account has no reason to receive a notification, the account plugin ends up polling continuously, desperately, and unsuccessfully trying to find a reason to notify. That leads to unnecessary CPU utilization. The reason is an apparent think-o in the code. The code tracks the last time a notification was shown, so it knows when to show the next notification later, even if the notification period, or account policy is updated by the admin in the interim. The problem is that it's wrong to look at the last notification time if there's no reason to show a notification. In that case the wakeup is merely to poll updates on the account policy. This commit addresses the problem by only looking at the previous notification time, if it was within the current notification period. --- plugins/account/gsd-account-manager.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/account/gsd-account-manager.c b/plugins/account/gsd-account-manager.c index ff054edd..b48c0fe8 100644 --- a/plugins/account/gsd-account-manager.c +++ b/plugins/account/gsd-account-manager.c @@ -207,65 +207,73 @@ out: } static gboolean set_policy_number (gint64 *destination, gint64 source) { if (*destination == source) return FALSE; *destination = source; return TRUE; } static gboolean on_notify_period_elapsed (GsdAccountManager *manager) { manager->priv->notify_period_timeout_id = 0; fetch_password_expiration_policy (manager); return G_SOURCE_REMOVE; } static void queue_periodic_timeout (GsdAccountManager *manager) { if (manager->priv->notify_period_timeout_id != 0) { g_source_remove (manager->priv->notify_period_timeout_id); manager->priv->notify_period_timeout_id = 0; } if (manager->priv->notify_period > 0) { - gint64 already_elapsed_time; + gint64 seconds_since_last_notification; + guint seconds_between_notifications; + guint seconds_until_next_notification; - already_elapsed_time = MAX (0, (g_get_monotonic_time () - manager->priv->last_notify_time) / G_USEC_PER_SEC); + seconds_since_last_notification = MAX (0, (g_get_monotonic_time () - manager->priv->last_notify_time) / G_USEC_PER_SEC); + seconds_between_notifications = manager->priv->notify_period * 60; - manager->priv->notify_period_timeout_id = g_timeout_add_seconds (MAX (0, manager->priv->notify_period * 60 - already_elapsed_time), + if (seconds_since_last_notification > seconds_between_notifications) + seconds_until_next_notification = seconds_between_notifications; + else + seconds_until_next_notification = seconds_between_notifications - seconds_since_last_notification; + + manager->priv->notify_period_timeout_id = g_timeout_add_seconds (seconds_until_next_notification, (GSourceFunc) on_notify_period_elapsed, manager); } } static void on_got_password_expiration_policy (GsdAccountsUser *accounts_user_proxy, GAsyncResult *res, gpointer user_data) { GsdAccountManager *manager = user_data; g_autoptr(GError) error = NULL; gboolean succeeded; gint64 expiration_time; gint64 last_change_time; gint64 min_days_between_changes; gint64 max_days_between_changes; gint64 days_to_warn; gint64 days_after_expiration_until_lock; gnome_settings_profile_start (NULL); succeeded = gsd_accounts_user_call_get_password_expiration_policy_finish (accounts_user_proxy, &expiration_time, &last_change_time, &min_days_between_changes, &max_days_between_changes, &days_to_warn, &days_after_expiration_until_lock, res, &error); -- 2.17.1