# HG changeset patch # User Guido Berhoerster # Date 1567079327 -7200 # Node ID 9905d4ae351c9ce4b76662fe649cb0fca89b7c5c # Parent 811df672633d543273b62fcd77fd57dee38513fb Fix continuos loop of update checks if the refresh cache interval is 0 If the interval for refreshing the cache is set to 0 each check for available updates refreshes the cache and causes an "updates-changed" signal to be emitted after a short delay which in turn triggers another check for updates. The "updates-changed" signal does not actually mean that the number of available updates has changed but rather that the package metadata cache has been invalidated. Fix this by blocking the "updates-changed" signal handler from when a periodic or irregular check is started until 4 seconds after it has finished. This is necessary since the signal will be delivered with a delay after a transaction has been completed. In addition prevent checks for updates triggered by the "updates-changed" signal from refreshing the cache even the interval is 0 since the emission of the signal implies that the cache has just been refreshed. diff -r 811df672633d -r 9905d4ae351c pui-backend.c --- a/pui-backend.c Wed Aug 28 13:29:23 2019 +0200 +++ b/pui-backend.c Thu Aug 29 13:48:47 2019 +0200 @@ -36,7 +36,8 @@ #include "pui-get-updates.h" #include "pui-types.h" -#define LOW_BATTERY_THRESHOLD 10.0 +#define LOW_BATTERY_THRESHOLD 10.0 /* % */ +#define UPDATES_CHANGED_UNBLOCK_DELAY 4 /* s */ struct _PuiBackend { GObject parent_instance; @@ -56,7 +57,8 @@ PkNetworkEnum network_state; gboolean inhibited; gboolean is_battery_low; - guint periodic_check_id; + guint check_id; + guint unblock_updates_changed_id; guint refresh_interval; gboolean use_mobile_connection; guint important_updates; @@ -90,6 +92,7 @@ static GParamSpec *properties[PROP_LAST] = { NULL }; static gboolean periodic_check(gpointer); +static void on_updates_changed(PkControl *, gpointer); GQuark pui_backend_error_quark(void) @@ -120,6 +123,18 @@ } } +static gboolean +unblock_updates_changed(gpointer user_data) +{ + PuiBackend *self = user_data; + + g_signal_handlers_unblock_by_func(self->pk_control, on_updates_changed, + self); + self->unblock_updates_changed_id = 0; + + return (G_SOURCE_REMOVE); +} + static void on_get_updates_finished(GObject *source_object, GAsyncResult *async_result, gpointer user_data) @@ -172,16 +187,55 @@ /* reschedule periodic check */ if (!self->inhibited) { - self->periodic_check_id = + self->check_id = g_timeout_add_seconds(PUI_CHECK_UPDATES_INTERVAL, periodic_check, self); } + /* handle get-updates signals again after a short delay */ + self->unblock_updates_changed_id = + g_timeout_add_seconds(UPDATES_CHANGED_UNBLOCK_DELAY, + unblock_updates_changed, self); + if (package_list != NULL) { g_ptr_array_unref(package_list); } } +static void +run_check(PuiBackend *self, gboolean refresh_cache) +{ + /* block any get-updates signals emitted when refreshing the cache */ + if (self->unblock_updates_changed_id != 0) { + /* still blocked */ + g_source_remove(self->unblock_updates_changed_id); + self->unblock_updates_changed_id = 0; + } else { + g_signal_handlers_block_by_func(self->pk_control, + G_CALLBACK(on_updates_changed), self); + } + + self->cancellable = g_cancellable_new(); + pui_get_updates_async(self->pk_control, + refresh_cache ? self->refresh_interval : G_MAXUINT, + self->cancellable, on_get_updates_finished, self); + + /* next periodic check will be scheduled after completion */ + self->check_id = 0; +} + +static gboolean +irregular_check(gpointer user_data) +{ + PuiBackend *self = user_data; + + g_debug("running check"); + + run_check(self, FALSE); + + return (G_SOURCE_REMOVE); +} + static gboolean periodic_check(gpointer user_data) { @@ -189,12 +243,7 @@ g_debug("running periodic check"); - self->cancellable = g_cancellable_new(); - pui_get_updates_async(self->pk_control, self->refresh_interval, - self->cancellable, on_get_updates_finished, self); - - /* next periodic check will be scheduled after completion */ - self->periodic_check_id = 0; + run_check(self, TRUE); return (G_SOURCE_REMOVE); } @@ -217,8 +266,8 @@ self->inhibited = inhibited; if (inhibited) { /* cancel periodic checks */ - if (self->periodic_check_id != 0) { - g_source_remove(self->periodic_check_id); + if (self->check_id != 0) { + g_source_remove(self->check_id); } /* cancel running operation */ @@ -239,7 +288,7 @@ remaining_time = (elapsed_time < PUI_CHECK_UPDATES_INTERVAL) ? PUI_CHECK_UPDATES_INTERVAL - elapsed_time : PUI_STARTUP_DELAY; - self->periodic_check_id = g_timeout_add_seconds(remaining_time, + self->check_id = g_timeout_add_seconds(remaining_time, periodic_check, self); } } @@ -301,9 +350,14 @@ { PuiBackend *self = PUI_BACKEND(object); - if (self->periodic_check_id != 0) { - g_source_remove(self->periodic_check_id); - self->periodic_check_id = 0; + if (self->check_id != 0) { + g_source_remove(self->check_id); + self->check_id = 0; + } + + if (self->unblock_updates_changed_id != 0) { + g_source_remove(self->unblock_updates_changed_id); + self->unblock_updates_changed_id = 0; } if (self->transaction_list != NULL) { @@ -493,19 +547,18 @@ { PuiBackend *self = user_data; - g_debug("number of updates changed"); + g_debug("package metatdata cache invalidated"); /* * schedule a check after a short delay so that a rapid succession of * signals is coalesced */ if (!self->inhibited) { - if (self->periodic_check_id != 0) { - g_source_remove(self->periodic_check_id); + if (self->check_id != 0) { + g_source_remove(self->check_id); } - self->periodic_check_id = - g_timeout_add_seconds(PUI_STARTUP_DELAY, periodic_check, - self); + self->check_id = g_timeout_add_seconds(PUI_STARTUP_DELAY, + irregular_check, self); } } @@ -639,7 +692,7 @@ /* get notification when the network state changes */ g_signal_connect(self->pk_control, "notify::network-state", G_CALLBACK(on_notify_network_state), self); - /* get notifications when the available package updates change */ + /* get notifications when the package metatdata cache is invalidated */ g_signal_connect(self->pk_control, "updates-changed", G_CALLBACK(on_updates_changed), self); /* get notifications when an application restart is required */