[PackageKit/f21] Backport some patches from master to fix some common crashers

Richard Hughes rhughes at fedoraproject.org
Thu Dec 11 20:15:54 UTC 2014


commit c68a371c17ad292bb27632f61dbb7860bdd97e64
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Dec 11 19:53:54 2014 +0000

    Backport some patches from master to fix some common crashers

 PackageKit.spec |    9 +-
 master.patch    |  727 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 735 insertions(+), 1 deletions(-)
---
diff --git a/PackageKit.spec b/PackageKit.spec
index b1a84e9..b40d768 100644
--- a/PackageKit.spec
+++ b/PackageKit.spec
@@ -7,7 +7,7 @@
 Summary:   Package management service
 Name:      PackageKit
 Version:   1.0.3
-Release:   3%{?dist}
+Release:   4%{?dist}
 License:   GPLv2+ and LGPLv2+
 URL:       http://www.freedesktop.org/software/PackageKit/
 Source0:   http://www.freedesktop.org/software/PackageKit/releases/%{name}-%{version}.tar.xz
@@ -20,6 +20,9 @@ Source1:   cached-metadata.tar
 # Fedora-specific: set Vendor.conf up for Fedora.
 Patch0:    PackageKit-0.3.8-Fedora-Vendor.conf.patch
 
+# already upstream
+Patch1:    master.patch
+
 Requires: %{name}-glib%{?_isa} = %{version}-%{release}
 Requires: shared-mime-info
 Requires: comps-extras
@@ -176,6 +179,7 @@ using PackageKit.
 %prep
 %setup -q
 %patch0 -p1 -b .fedora
+%patch1 -p1 -b .master
 
 %build
 %configure \
@@ -316,6 +320,9 @@ systemctl disable packagekit-offline-update.service > /dev/null 2>&1 || :
 %{_datadir}/gtk-doc/html/PackageKit
 
 %changelog
+* Thu Dec 11 2014 Richard Hughes <rhughes at redhat.com> - 1.0.3-4
+- Backport some patches from master to fix some common crashers.
+
 * Mon Nov 17 2014 Kalev Lember <kalevlember at gmail.com> - 1.0.3-3
 - Update cached metadata in preparation for F21 release
 
diff --git a/master.patch b/master.patch
new file mode 100644
index 0000000..ae8eb72
--- /dev/null
+++ b/master.patch
@@ -0,0 +1,727 @@
+commit 0e85001b247c2ed933e5eb028cd167a8e3e40589
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Nov 26 10:58:17 2014 +0000
+
+    command-not-found: Do not attempt to run for anything prefixed with '.'
+    
+    Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1151185
+
+diff --git a/contrib/command-not-found/pk-command-not-found.c b/contrib/command-not-found/pk-command-not-found.c
+index ef1997e..0843735 100644
+--- a/contrib/command-not-found/pk-command-not-found.c
++++ b/contrib/command-not-found/pk-command-not-found.c
+@@ -778,6 +778,8 @@ main (int argc, char *argv[])
+ 	len = strlen (argv[1]);
+ 	if (len < 1)
+ 		goto out;
++	if (argv[1][0] == '.')
++		goto out;
+ 
+ 	/* TRANSLATORS: the prefix of all the output telling the user
+ 	 * why it's not executing. NOTE: this is lowercase to mimic
+commit e2c38732cddd3322470dd7ac008debc9158e98c2
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Dec 3 15:39:25 2014 +0000
+
+    hif: Proxy the allow-cancel state from the state to the job
+
+diff --git a/backends/hif/pk-backend-hif.c b/backends/hif/pk-backend-hif.c
+index 9b7fef1..0aa02df 100644
+--- a/backends/hif/pk-backend-hif.c
++++ b/backends/hif/pk-backend-hif.c
+@@ -353,6 +353,17 @@ pk_backend_speed_changed_cb (HifState *state,
+ }
+ 
+ /**
++ * pk_backend_state_allow_cancel_changed_cb:
++ **/
++static void
++pk_backend_state_allow_cancel_changed_cb (HifState *state,
++					  gboolean allow_cancel,
++					  PkBackendJob *job)
++{
++	pk_backend_job_set_allow_cancel (job, allow_cancel);
++}
++
++/**
+  * pk_backend_start_job:
+  */
+ void
+@@ -373,6 +384,9 @@ pk_backend_start_job (PkBackend *backend, PkBackendJob *job)
+ 	g_signal_connect (job_data->state, "action-changed",
+ 			  G_CALLBACK (pk_backend_state_action_changed_cb),
+ 			  job);
++	g_signal_connect (job_data->state, "allow-cancel-changed",
++			  G_CALLBACK (pk_backend_state_allow_cancel_changed_cb),
++			  job);
+ 	g_signal_connect (job_data->state, "notify::speed",
+ 			  G_CALLBACK (pk_backend_speed_changed_cb),
+ 			  job);
+commit b7a1701ac626192fedb376b7b3a7401cf6c59aeb
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Dec 3 17:11:45 2014 +0000
+
+    Save the correct logind cookie when perforing the system-wide inhibit
+    
+    It seem we need to use g_dbus_proxy_call_with_unix_fd_list_sync() to actually
+    get the FD number now. This is also the method gnome-session uses.
+
+diff --git a/src/pk-engine.c b/src/pk-engine.c
+index e434c88..8dea882 100644
+--- a/src/pk-engine.c
++++ b/src/pk-engine.c
+@@ -37,6 +37,7 @@
+ 
+ #include <glib/gi18n.h>
+ #include <glib/gstdio.h>
++#include <gio/gunixfdlist.h>
+ #include <packagekit-glib2/pk-offline.h>
+ #include <packagekit-glib2/pk-offline-private.h>
+ #include <packagekit-glib2/pk-version.h>
+@@ -262,9 +263,16 @@ static void
+ pk_engine_inhibit (PkEngine *engine)
+ {
+ #ifdef HAVE_SYSTEMD
++	const gint *fd_list;
++	gint fd_list_len = 0;
+ 	_cleanup_error_free_ GError *error = NULL;
++	_cleanup_object_unref_ GUnixFDList *out_fd_list = NULL;
+ 	_cleanup_variant_unref_ GVariant *res = NULL;
+ 
++	/* already inhibited */
++	if (engine->priv->logind_fd != 0)
++		return;
++
+ 	/* not yet connected */
+ 	if (engine->priv->logind_proxy == NULL) {
+ 		g_warning ("no logind connection to use");
+@@ -272,25 +280,32 @@ pk_engine_inhibit (PkEngine *engine)
+ 	}
+ 
+ 	/* block shutdown and idle */
+-	res = g_dbus_proxy_call_sync (engine->priv->logind_proxy,
+-				      "Inhibit",
+-				      g_variant_new ("(ssss)",
+-						     "shutdown:idle",
+-						     "Package Updater",
+-						     "Package Update in Progress",
+-						     "block"),
+-				      G_DBUS_CALL_FLAGS_NONE,
+-				      -1,
+-				      NULL, /* GCancellable */
+-				      &error);
++	res = g_dbus_proxy_call_with_unix_fd_list_sync (engine->priv->logind_proxy,
++							"Inhibit",
++							g_variant_new ("(ssss)",
++								       "shutdown:idle",
++								       "Package Updater",
++								       "Package Update in Progress",
++								       "block"),
++							G_DBUS_CALL_FLAGS_NONE,
++							-1,
++							NULL, /* fd_list */
++							&out_fd_list,
++							NULL, /* GCancellable */
++							&error);
+ 	if (res == NULL) {
+ 		g_warning ("Failed to Inhibit using logind: %s", error->message);
+ 		return;
+ 	}
+ 
+ 	/* keep fd as cookie */
+-	g_variant_get (res, "(h)", &engine->priv->logind_fd);
+-	g_debug ("got logind cookie %i", engine->priv->logind_fd);
++	fd_list = g_unix_fd_list_peek_fds (out_fd_list, &fd_list_len);
++	if (fd_list_len != 1) {
++		g_warning ("invalid response from logind");
++		return;
++	}
++	engine->priv->logind_fd = fd_list[0];
++	g_debug ("opened logind fd %i", engine->priv->logind_fd);
+ #endif
+ }
+ 
+@@ -301,10 +316,9 @@ static void
+ pk_engine_uninhibit (PkEngine *engine)
+ {
+ #ifdef HAVE_SYSTEMD
+-	if (engine->priv->logind_fd == 0) {
+-		g_warning ("no fd to close");
++	if (engine->priv->logind_fd == 0)
+ 		return;
+-	}
++	g_debug ("closed logind fd %i", engine->priv->logind_fd);
+ 	close (engine->priv->logind_fd);
+ 	engine->priv->logind_fd = 0;
+ #endif
+commit 8e314593fcf87e276b87bb7f5a9c8710883124a6
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Dec 3 17:15:03 2014 +0000
+
+    trivial: Fix a method name to reflect the new name
+
+diff --git a/src/pk-engine.c b/src/pk-engine.c
+index 8dea882..dcb4686 100644
+--- a/src/pk-engine.c
++++ b/src/pk-engine.c
+@@ -162,10 +162,10 @@ pk_engine_reset_timer (PkEngine *engine)
+ }
+ 
+ /**
+- * pk_engine_transaction_list_changed_cb:
++ * pk_engine_scheduler_changed_cb:
+  **/
+ static void
+-pk_engine_transaction_list_changed_cb (PkScheduler *tlist, PkEngine *engine)
++pk_engine_scheduler_changed_cb (PkScheduler *tlist, PkEngine *engine)
+ {
+ 	_cleanup_strv_free_ gchar **transaction_list = NULL;
+ 	gboolean locked;
+@@ -1875,7 +1875,7 @@ pk_engine_new (GKeyFile *conf)
+ 	pk_scheduler_set_backend (engine->priv->scheduler,
+ 				  engine->priv->backend);
+ 	g_signal_connect (engine->priv->scheduler, "changed",
+-			  G_CALLBACK (pk_engine_transaction_list_changed_cb), engine);
++			  G_CALLBACK (pk_engine_scheduler_changed_cb), engine);
+ 	return PK_ENGINE (engine);
+ }
+ 
+commit 1c019c15929781158cdd6ee67401dd168d34b7d3
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Dec 3 17:20:16 2014 +0000
+
+    Actually inhibit logind when the transaction can't be cancelled
+    
+    To do this we have to proxy the allow-cancel state up to the scheduler, and then
+    if any running tasks cannot be cancelled we take the logind inhibit.
+    
+    This also means making the initial and final allow-cancel states sane so that
+    the inihibit is registered when required, and also disposed of if not done so
+    manually.
+    
+    This commit also unties the confusion between "locked" and "allow-cancel" that
+    existed in multiple places.
+    Backends should use 'allow-cancel' for things actions that cannot be cancelled
+    manually (nor will be the system be allowed to shutdown) and 'locked' for where
+    the package cache is shared and cannot be used by other tools.
+
+diff --git a/src/pk-backend-job.c b/src/pk-backend-job.c
+index af9e9a7..37ee96f 100644
+--- a/src/pk-backend-job.c
++++ b/src/pk-backend-job.c
+@@ -131,6 +131,7 @@ pk_backend_job_reset (PkBackendJob *job)
+ 	job->priv->finished = FALSE;
+ 	job->priv->has_sent_package = FALSE;
+ 	job->priv->set_error = FALSE;
++	job->priv->allow_cancel = TRUE;
+ 	job->priv->thread = NULL;
+ 	job->priv->exit = PK_EXIT_ENUM_UNKNOWN;
+ 	job->priv->role = PK_ROLE_ENUM_UNKNOWN;
+@@ -1711,15 +1712,15 @@ pk_backend_job_set_allow_cancel (PkBackendJob *job, gboolean allow_cancel)
+ 	}
+ 
+ 	/* same as last state? */
+-	if (job->priv->allow_cancel == (gboolean) allow_cancel)
++	if (job->priv->allow_cancel == allow_cancel)
+ 		return;
+ 
+ 	/* emit */
++	job->priv->allow_cancel = allow_cancel;
+ 	pk_backend_job_call_vfunc (job,
+ 				   PK_BACKEND_SIGNAL_ALLOW_CANCEL,
+ 				   GUINT_TO_POINTER (allow_cancel),
+ 				   NULL);
+-	job->priv->allow_cancel = allow_cancel;
+ }
+ 
+ /**
+@@ -1813,8 +1814,8 @@ pk_backend_job_finished (PkBackendJob *job)
+ 		g_warning ("required status signals for %s!", role_text);
+ 	}
+ 
+-	/* make any UI insensitive */
+-	pk_backend_job_set_allow_cancel (job, FALSE);
++	/* drop any inhibits */
++	pk_backend_job_set_allow_cancel (job, TRUE);
+ 
+ 	/* mark as finished for the UI that might only be watching status */
+ 	pk_backend_job_set_status (job, PK_STATUS_ENUM_FINISHED);
+diff --git a/src/pk-engine.c b/src/pk-engine.c
+index dcb4686..92b020f 100644
+--- a/src/pk-engine.c
++++ b/src/pk-engine.c
+@@ -161,22 +161,39 @@ pk_engine_reset_timer (PkEngine *engine)
+ 	g_timer_reset (engine->priv->timer);
+ }
+ 
++static void pk_engine_inhibit (PkEngine *engine);
++static void pk_engine_uninhibit (PkEngine *engine);
++
++/**
++ * pk_engine_set_inhibited:
++ **/
++static void
++pk_engine_set_inhibited (PkEngine *engine, gboolean inhibited)
++{
++	g_return_if_fail (PK_IS_ENGINE (engine));
++
++	/* inhibit shutdown and suspend */
++	if (inhibited)
++		pk_engine_inhibit (engine);
++	else
++		pk_engine_uninhibit (engine);
++}
++
+ /**
+  * pk_engine_scheduler_changed_cb:
+  **/
+ static void
+-pk_engine_scheduler_changed_cb (PkScheduler *tlist, PkEngine *engine)
++pk_engine_scheduler_changed_cb (PkScheduler *scheduler, PkEngine *engine)
+ {
+ 	_cleanup_strv_free_ gchar **transaction_list = NULL;
+-	gboolean locked;
+ 
+ 	g_return_if_fail (PK_IS_ENGINE (engine));
+ 
+ 	/* automatically locked if the transaction cannot be cancelled */
+-	locked = pk_scheduler_get_locked (tlist);
+-	pk_engine_set_locked (engine, locked);
++	pk_engine_set_locked (engine, pk_scheduler_get_locked (scheduler));
++	pk_engine_set_inhibited (engine, pk_scheduler_get_inhibited (scheduler));
+ 
+-	transaction_list = pk_scheduler_get_array (engine->priv->scheduler);
++	transaction_list = pk_scheduler_get_array (scheduler);
+ 	g_dbus_connection_emit_signal (engine->priv->connection,
+ 				       NULL,
+ 				       PK_DBUS_PATH,
+@@ -337,12 +354,6 @@ pk_engine_set_locked (PkEngine *engine, gboolean is_locked)
+ 		return;
+ 	engine->priv->locked = is_locked;
+ 
+-	/* inhibit shutdown and suspend */
+-	if (is_locked)
+-		pk_engine_inhibit (engine);
+-	else
+-		pk_engine_uninhibit (engine);
+-
+ 	/* emit */
+ 	pk_engine_emit_property_changed (engine,
+ 					 "Locked",
+diff --git a/src/pk-scheduler.c b/src/pk-scheduler.c
+index c9415ef..fa81a97 100644
+--- a/src/pk-scheduler.c
++++ b/src/pk-scheduler.c
+@@ -105,6 +105,7 @@ typedef struct {
+ 	guint			 commit_id;
+ 	gulong			 finished_id;
+ 	gulong			 state_changed_id;
++	gulong			 allow_cancel_changed_id;
+ 	guint			 uid;
+ 	guint			 tries;
+ } PkSchedulerItem;
+@@ -202,6 +203,8 @@ pk_scheduler_item_free (PkSchedulerItem *item)
+ 		g_signal_handler_disconnect (item->transaction, item->finished_id);
+ 	if (item->state_changed_id != 0)
+ 		g_signal_handler_disconnect (item->transaction, item->state_changed_id);
++	if (item->allow_cancel_changed_id != 0)
++		g_signal_handler_disconnect (item->transaction, item->allow_cancel_changed_id);
+ 	g_object_unref (item->transaction);
+ 	if (item->commit_id != 0)
+ 		g_source_remove (item->commit_id);
+@@ -514,6 +517,18 @@ pk_scheduler_commit (PkScheduler *scheduler, const gchar *tid)
+ }
+ 
+ /**
++ * pk_scheduler_transaction_allow_cancel_changed_cb:
++ **/
++static void
++pk_scheduler_transaction_allow_cancel_changed_cb (PkTransaction *transaction,
++					          gboolean allow_cancel,
++					          PkScheduler *scheduler)
++{
++	/* just proxy this back up */
++	g_signal_emit (scheduler, signals [PK_SCHEDULER_CHANGED], 0);
++}
++
++/**
+  * pk_scheduler_transaction_state_changed_cb:
+  **/
+ static void
+@@ -678,6 +693,10 @@ pk_scheduler_create (PkScheduler *scheduler,
+ 		g_signal_connect_after (item->transaction, "state-changed",
+ 					G_CALLBACK (pk_scheduler_transaction_state_changed_cb),
+ 					scheduler);
++	item->allow_cancel_changed_id =
++		g_signal_connect_after (item->transaction, "allow-cancel-changed",
++					G_CALLBACK (pk_scheduler_transaction_allow_cancel_changed_cb),
++					scheduler);
+ 
+ 	/* set transaction state */
+ 	pk_transaction_set_state (item->transaction, PK_TRANSACTION_STATE_NEW);
+@@ -736,7 +755,7 @@ pk_scheduler_create (PkScheduler *scheduler,
+  * pk_scheduler_get_locked:
+  *
+  * Return value: %TRUE if any of the transactions in progress are
+- * locking a database or resource and cannot be cancelled.
++ * locking the packaging system.
+  **/
+ gboolean
+ pk_scheduler_get_locked (PkScheduler *scheduler)
+@@ -748,19 +767,43 @@ pk_scheduler_get_locked (PkScheduler *scheduler)
+ 
+ 	g_return_val_if_fail (PK_IS_SCHEDULER (scheduler), FALSE);
+ 
+-	/* anything running? */
++	/* check if any backend in running transaction is locked at time */
+ 	array = pk_scheduler_get_active_transactions (scheduler);
+-	if (array->len == 0)
+-		return FALSE;
++	for (i = 0; i < array->len; i++) {
++		item = g_ptr_array_index (array, i);
++		job = pk_transaction_get_backend_job (item->transaction);
++		if (job == NULL)
++			continue;
++		if (pk_backend_job_get_locked (job))
++			return TRUE;
++	}
++	return FALSE;
++}
++
++/**
++ * pk_scheduler_get_inhibited:
++ *
++ * Return value: %TRUE if any of the transactions in progress cannot be
++ * cancelled.
++ **/
++gboolean
++pk_scheduler_get_inhibited (PkScheduler *scheduler)
++{
++	PkBackendJob *job;
++	PkSchedulerItem *item;
++	guint i;
++	_cleanup_ptrarray_unref_ GPtrArray *array = NULL;
++
++	g_return_val_if_fail (PK_IS_SCHEDULER (scheduler), FALSE);
+ 
+ 	/* check if any backend in running transaction is locked at time */
++	array = pk_scheduler_get_active_transactions (scheduler);
+ 	for (i = 0; i < array->len; i++) {
+-		item = (PkSchedulerItem *) g_ptr_array_index (array, i);
+-
++		item = g_ptr_array_index (array, i);
+ 		job = pk_transaction_get_backend_job (item->transaction);
+ 		if (job == NULL)
+ 			continue;
+-		if (pk_backend_job_get_locked (job))
++		if (!pk_backend_job_get_allow_cancel (job))
+ 			return TRUE;
+ 	}
+ 	return FALSE;
+diff --git a/src/pk-scheduler.h b/src/pk-scheduler.h
+index 398e4ff..d394dc8 100644
+--- a/src/pk-scheduler.h
++++ b/src/pk-scheduler.h
+@@ -68,6 +68,7 @@ gchar		*pk_scheduler_get_state		(PkScheduler	*scheduler)
+ 						 G_GNUC_WARN_UNUSED_RESULT;
+ guint		 pk_scheduler_get_size		(PkScheduler	*scheduler);
+ gboolean	 pk_scheduler_get_locked	(PkScheduler	*scheduler);
++gboolean	 pk_scheduler_get_inhibited	(PkScheduler	*scheduler);
+ PkTransaction	*pk_scheduler_get_transaction	(PkScheduler	*scheduler,
+ 						 const gchar	*tid);
+ void		 pk_scheduler_cancel_background	(PkScheduler	*scheduler);
+diff --git a/src/pk-transaction.c b/src/pk-transaction.c
+index 6485bb5..33245d8 100644
+--- a/src/pk-transaction.c
++++ b/src/pk-transaction.c
+@@ -170,6 +170,7 @@ typedef enum {
+ enum {
+ 	SIGNAL_FINISHED,
+ 	SIGNAL_STATE_CHANGED,
++	SIGNAL_ALLOW_CANCEL_CHANGED,
+ 	SIGNAL_LAST
+ };
+ 
+@@ -384,7 +385,8 @@ pk_transaction_allow_cancel_emit (PkTransaction *transaction, gboolean allow_can
+ 
+ 	transaction->priv->allow_cancel = allow_cancel;
+ 
+-	/* TODO: have master property on main interface */
++	/* proxy this up so we can change the system inhibit */
++	g_signal_emit (transaction, signals[SIGNAL_ALLOW_CANCEL_CHANGED], 0, allow_cancel);
+ 
+ 	/* emit */
+ 	pk_transaction_emit_property_changed (transaction,
+@@ -1101,10 +1103,6 @@ pk_transaction_finished_cb (PkBackendJob *job, PkExitEnum exit_enum, PkTransacti
+ 		pk_transaction_offline_finished (transaction);
+ 	}
+ 
+-	/* if we did not send this, ensure the GUI has the right state */
+-	if (transaction->priv->allow_cancel)
+-		pk_transaction_allow_cancel_emit (transaction, FALSE);
+-
+ 	/* we should get no more from the backend with this tid */
+ 	transaction->priv->finished = TRUE;
+ 
+@@ -1796,9 +1794,6 @@ pk_transaction_run (PkTransaction *transaction)
+ 		 priv->tid,
+ 		 pk_role_enum_to_string (priv->role));
+ 
+-	/* mark running */
+-	priv->allow_cancel = FALSE;
+-
+ 	/* reset after the pre-transaction checks */
+ 	pk_backend_job_set_percentage (priv->job, PK_BACKEND_PERCENTAGE_INVALID);
+ 
+@@ -5408,6 +5403,11 @@ pk_transaction_class_init (PkTransactionClass *klass)
+ 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ 			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+ 			      G_TYPE_NONE, 1, G_TYPE_UINT);
++	signals[SIGNAL_ALLOW_CANCEL_CHANGED] =
++		g_signal_new ("allow-cancel-changed",
++			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
++			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
++			      G_TYPE_NONE, 1, G_TYPE_UINT);
+ 
+ 	g_type_class_add_private (klass, sizeof (PkTransactionPrivate));
+ }
+commit 85a02c15fb1bf05e109d53ecd02b38baf410408a
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Wed Dec 10 18:12:27 2014 +0000
+
+    Make pk_backend_repo_list_changed() threadsafe
+
+diff --git a/src/pk-backend.c b/src/pk-backend.c
+index 78191c1..4c45f0f 100644
+--- a/src/pk-backend.c
++++ b/src/pk-backend.c
+@@ -210,6 +210,8 @@ struct PkBackendPrivate
+ 	GMutex			 thread_hash_mutex;
+ 	gboolean		 transaction_in_progress;
+ 	guint			 transaction_inhibit_end_idle_id;
++	guint			 repo_list_changed_id;
++	guint			 installed_db_changed_id;
+ };
+ 
+ G_DEFINE_TYPE (PkBackend, pk_backend, G_TYPE_OBJECT)
+@@ -633,20 +635,58 @@ pk_backend_unload (PkBackend *backend)
+ }
+ 
+ /**
+- * pk_backend_repo_list_changed:
++ * pk_backend_repo_list_changed_cb:
+  **/
+-void
+-pk_backend_repo_list_changed (PkBackend *backend)
++static gboolean
++pk_backend_repo_list_changed_cb (gpointer user_data)
+ {
++	PkBackend *backend = PK_BACKEND (user_data);
+ #ifdef PK_BUILD_DAEMON
+ 	_cleanup_object_unref_ PkNotify *notify = NULL;
++	notify = pk_notify_new ();
++	pk_notify_repo_list_changed (notify);
++#endif
++	backend->priv->repo_list_changed_id = 0;
++	return FALSE;
++}
+ 
++/**
++ * pk_backend_repo_list_changed:
++ *
++ * This function can be called on any thread.
++ **/
++void
++pk_backend_repo_list_changed (PkBackend *backend)
++{
+ 	g_return_if_fail (PK_IS_BACKEND (backend));
+ 	g_return_if_fail (backend->priv->loaded);
+ 
+-	notify = pk_notify_new ();
+-	pk_notify_repo_list_changed (notify);
+-#endif
++	/* already scheduled */
++	if (backend->priv->repo_list_changed_id != 0)
++		return;
++
++	/* idle add */
++	backend->priv->repo_list_changed_id =
++		g_idle_add (pk_backend_repo_list_changed_cb, backend);
++
++}
++
++/**
++ * pk_backend_installed_db_changed_cb:
++ **/
++static gboolean
++pk_backend_installed_db_changed_cb (gpointer user_data)
++{
++	PkBackend *backend = PK_BACKEND (user_data);
++	_cleanup_error_free_ GError *error = NULL;
++
++	if (!backend->priv->transaction_in_progress) {
++		g_debug ("invalidating offline updates");
++		if (!pk_offline_auth_invalidate (&error))
++			g_warning ("failed to invalidate: %s", error->message);
++	}
++	backend->priv->installed_db_changed_id = 0;
++	return FALSE;
+ }
+ 
+ /**
+@@ -661,20 +701,22 @@ pk_backend_repo_list_changed (PkBackend *backend)
+  * transactions done by PackageKit itself, a backend would call
+  * pk_backend_transaction_inhibit_start() before each transaction and
+  * pk_backend_transaction_inhibit_end() after the transaction has finished.
++ *
++ * This function can be called on any thread.
+  **/
+ void
+ pk_backend_installed_db_changed (PkBackend *backend)
+ {
+-	_cleanup_error_free_ GError *error = NULL;
+-
+ 	g_return_if_fail (PK_IS_BACKEND (backend));
+ 	g_return_if_fail (backend->priv->loaded);
+ 
+-	if (!backend->priv->transaction_in_progress) {
+-		g_debug ("invalidating offline updates");
+-		if (!pk_offline_auth_invalidate (&error))
+-			g_warning ("failed to invalidate: %s", error->message);
+-	}
++	/* already scheduled */
++	if (backend->priv->installed_db_changed_id != 0)
++		return;
++
++	/* idle add */
++	backend->priv->installed_db_changed_id =
++		g_idle_add (pk_backend_installed_db_changed_cb, backend);
+ }
+ 
+ /**
+commit 52dbba80288f292909b6af0f20a78ada498ca213
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Thu Dec 11 10:11:33 2014 +0000
+
+    Fix a hard-to-debug crash when cancelling a task that has never been run
+    
+    Calling g_dbus_method_invocation_return_value() twice for the same
+    GDBusMethodInvocation is a bad idea that manifests in a backtrace like:
+    
+     > g_source_callback_unref (cb_data) at gmain.c:1532
+     > g_source_destroy_internal (source, context, have_lock=1) at gmain.c:1178
+     > g_main_context_dispatch (context) at gmain.c:3134
+    
+     > (gdb) p g_source_get_name(source)
+     > $1 = '[gio] call_in_idle_cb'
+
+diff --git a/src/pk-transaction.c b/src/pk-transaction.c
+index 0f3dd8d..93295de 100644
+--- a/src/pk-transaction.c
++++ b/src/pk-transaction.c
+@@ -2911,7 +2911,6 @@ skip_uid:
+ 						PK_ERROR_ENUM_TRANSACTION_CANCELLED,
+ 						msg);
+ 		pk_transaction_finished_emit (transaction, PK_EXIT_ENUM_CANCELLED, 0);
+-		pk_transaction_dbus_return (context, NULL);
+ 		goto out;
+ 	}
+ 
+commit 71a8f25ce05ee4d9177db288317e86512b989232
+Author: Richard Hughes <richard at hughsie.com>
+Date:   Thu Dec 11 10:31:57 2014 +0000
+
+    Make pk_backend_job_call_vfunc() threadsafe
+    
+    We have to keep a ref to PkBackendJob until the lifecycle is properly fixed.
+
+diff --git a/src/pk-backend-job.c b/src/pk-backend-job.c
+index 73162e4..c1c5ca6 100644
+--- a/src/pk-backend-job.c
++++ b/src/pk-backend-job.c
+@@ -657,6 +657,18 @@ pk_backend_job_signal_to_string (PkBackendJobSignal id)
+ }
+ 
+ /**
++ * pk_backend_job_vfunc_event_free:
++ **/
++static void
++pk_backend_job_vfunc_event_free (PkBackendJobVFuncHelper *helper)
++{
++	if (helper->destroy_func != NULL)
++		helper->destroy_func (helper->object);
++	g_object_unref (helper->job);
++	g_free (helper);
++}
++
++/**
+  * pk_backend_job_call_vfunc_idle_cb:
+  **/
+ static gboolean
+@@ -673,8 +685,6 @@ pk_backend_job_call_vfunc_idle_cb (gpointer user_data)
+ 		g_warning ("tried to do signal %s when no longer connected",
+ 			   pk_backend_job_signal_to_string (helper->signal_kind));
+ 	}
+-	if (helper->destroy_func != NULL)
+-		helper->destroy_func (helper->object);
+ 	return FALSE;
+ }
+ 
+@@ -693,25 +703,31 @@ pk_backend_job_call_vfunc (PkBackendJob *job,
+ 	PkBackendJobVFuncHelper *helper;
+ 	PkBackendJobVFuncItem *item;
+ 	guint priority = G_PRIORITY_DEFAULT_IDLE;
++	_cleanup_source_unref_ GSource *source = NULL;
+ 
+ 	/* call transaction vfunc if not disabled and set */
+ 	item = &job->priv->vfunc_items[signal_kind];
+ 	if (!item->enabled || item->vfunc == NULL)
+ 		return;
+ 
++	/* order this last if others are still pending */
+ 	if (signal_kind == PK_BACKEND_SIGNAL_FINISHED)
+ 		priority = G_PRIORITY_LOW;
+ 
+-	/* emit idle, TODO: do we ever need to cancel this? */
++	/* emit idle */
+ 	helper = g_new0 (PkBackendJobVFuncHelper, 1);
+-	helper->job = job;
++	helper->job = g_object_ref (job);
+ 	helper->signal_kind = signal_kind;
+ 	helper->object = object;
+ 	helper->destroy_func = destroy_func;
+-	g_idle_add_full (priority,
+-			 pk_backend_job_call_vfunc_idle_cb,
+-			 helper,
+-			 g_free);
++	source = g_idle_source_new ();
++	g_source_set_priority (source, priority);
++	g_source_set_callback (source,
++			       pk_backend_job_call_vfunc_idle_cb,
++			       helper,
++			       (GDestroyNotify) pk_backend_job_vfunc_event_free);
++	g_source_set_name (source, "[PkBackendJob] idle_event_cb");
++	g_source_attach (source, NULL);
+ }
+ 
+ /**
+diff --git a/src/pk-cleanup.h b/src/pk-cleanup.h
+index 7a04561..ee511dc 100644
+--- a/src/pk-cleanup.h
++++ b/src/pk-cleanup.h
+@@ -57,6 +57,7 @@ GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_
+ GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_keyfile_unref, g_key_file_unref)
+ GS_DEFINE_CLEANUP_FUNCTION0(GMarkupParseContext*, gs_local_markup_parse_context_unref, g_markup_parse_context_unref)
+ GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref)
++GS_DEFINE_CLEANUP_FUNCTION0(GSource*, gs_local_source_unref, g_source_unref)
+ GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref)
+ GS_DEFINE_CLEANUP_FUNCTION0(GTimer*, gs_local_destroy_timer, g_timer_destroy)
+ GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref)
+@@ -86,6 +87,7 @@ GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free)
+ #define _cleanup_keyfile_unref_ __attribute__ ((cleanup(gs_local_keyfile_unref)))
+ #define _cleanup_markup_parse_context_unref_ __attribute__ ((cleanup(gs_local_markup_parse_context_unref)))
+ #define _cleanup_object_unref_ __attribute__ ((cleanup(gs_local_obj_unref)))
++#define _cleanup_source_unref_ __attribute__ ((cleanup(gs_local_source_unref)))
+ #define _cleanup_ptrarray_unref_ __attribute__ ((cleanup(gs_local_ptrarray_unref)))
+ #define _cleanup_variant_unref_ __attribute__ ((cleanup(gs_local_variant_unref)))
+ #define _cleanup_main_loop_unref_ __attribute__ ((cleanup(gs_local_main_loop_unref)))


More information about the scm-commits mailing list