[PATCH 09/10] daemon: release resources at shutdown

Peter Wu peter at lekensteyn.nl
Wed Nov 26 03:21:16 PST 2014


This makes it easier to find real memory leaks with valgrind. After
calling the up_backend_unplug functions, you cannot restart it with
up_backend_coldplug since the lists are cleared.

Tested with Linux only (not on *BSD; dummy compiles).

https://bugs.freedesktop.org/show_bug.cgi?id=82659
---
 src/dummy/up-backend.c   | 20 ++++++++++++++++++++
 src/freebsd/up-backend.c | 24 ++++++++++++++++++++++++
 src/linux/up-backend.c   | 27 +++++++++++++++++++++++++++
 src/openbsd/up-backend.c | 16 ++++++++++++++++
 src/up-backend.h         |  1 +
 src/up-daemon.c          | 18 ++++++++++++++++++
 src/up-daemon.h          |  1 +
 src/up-device-list.c     | 31 +++++++++++++++++++++++++++++++
 src/up-device-list.h     |  2 ++
 src/up-device.c          | 16 ++++++++++++++++
 src/up-device.h          |  1 +
 src/up-main.c            |  1 +
 12 files changed, 158 insertions(+)

diff --git a/src/dummy/up-backend.c b/src/dummy/up-backend.c
index 342111b..ad81b0b 100644
--- a/src/dummy/up-backend.c
+++ b/src/dummy/up-backend.c
@@ -129,6 +129,26 @@ up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
 }
 
 /**
+ * up_backend_unplug:
+ * @backend: The %UpBackend class instance
+ *
+ * Forget about all learned devices, effectively undoing up_backend_coldplug.
+ * Resources are released without emitting signals.
+ */
+void
+up_backend_unplug (UpBackend *backend)
+{
+	if (backend->priv->device_list != NULL) {
+		g_object_unref (backend->priv->device_list);
+		backend->priv->device_list = NULL;
+	}
+	if (backend->priv->daemon != NULL) {
+		g_object_unref (backend->priv->daemon);
+		backend->priv->daemon = NULL;
+	}
+}
+
+/**
  * up_backend_get_critical_action:
  * @backend: The %UpBackend class instance
  *
diff --git a/src/freebsd/up-backend.c b/src/freebsd/up-backend.c
index ad54b9c..9fcd2b1 100644
--- a/src/freebsd/up-backend.c
+++ b/src/freebsd/up-backend.c
@@ -294,6 +294,30 @@ up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
 }
 
 /**
+ * up_backend_unplug:
+ * @backend: The %UpBackend class instance
+ *
+ * Forget about all learned devices, effectively undoing up_backend_coldplug.
+ * Resources are released without emitting signals.
+ */
+void
+up_backend_unplug (UpBackend *backend)
+{
+	if (backend->priv->poll_timer_id > 0) {
+		g_source_remove (backend->priv->poll_timer_id);
+		backend->priv->poll_timer_id = 0;
+	}
+	if (backend->priv->device_list != NULL) {
+		g_object_unref (backend->priv->device_list);
+		backend->priv->device_list = NULL;
+	}
+	if (backend->priv->daemon != NULL) {
+		g_object_unref (backend->priv->daemon);
+		backend->priv->daemon = NULL;
+	}
+}
+
+/**
  * up_backend_get_critical_action:
  * @backend: The %UpBackend class instance
  *
diff --git a/src/linux/up-backend.c b/src/linux/up-backend.c
index f45ce29..b7a129d 100644
--- a/src/linux/up-backend.c
+++ b/src/linux/up-backend.c
@@ -340,6 +340,33 @@ up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
 	return TRUE;
 }
 
+/**
+ * up_backend_unplug:
+ * @backend: The %UpBackend class instance
+ *
+ * Forget about all learned devices, effectively undoing up_backend_coldplug.
+ * Resources are released without emitting signals.
+ */
+void
+up_backend_unplug (UpBackend *backend)
+{
+	if (backend->priv->gudev_client != NULL) {
+		g_object_unref (backend->priv->gudev_client);
+		backend->priv->gudev_client = NULL;
+	}
+	if (backend->priv->device_list != NULL) {
+		g_object_unref (backend->priv->device_list);
+		backend->priv->device_list = NULL;
+	}
+	/* set in init, clear the list to remove reference to UpDaemon */
+	if (backend->priv->managed_devices != NULL)
+		up_device_list_clear (backend->priv->managed_devices, FALSE);
+	if (backend->priv->daemon != NULL) {
+		g_object_unref (backend->priv->daemon);
+		backend->priv->daemon = NULL;
+	}
+}
+
 static gboolean
 check_action_result (GVariant *result)
 {
diff --git a/src/openbsd/up-backend.c b/src/openbsd/up-backend.c
index 807bb2f..20e86c0 100644
--- a/src/openbsd/up-backend.c
+++ b/src/openbsd/up-backend.c
@@ -150,6 +150,22 @@ up_backend_coldplug (UpBackend *backend, UpDaemon *daemon)
 }
 
 /**
+ * up_backend_unplug:
+ * @backend: The %UpBackend class instance
+ *
+ * Forget about all learned devices, effectively undoing up_backend_coldplug.
+ * Resources are released without emitting signals.
+ */
+void
+up_backend_unplug (UpBackend *backend)
+{
+	if (backend->priv->daemon != NULL) {
+		g_object_unref (backend->priv->daemon);
+		backend->priv->daemon = NULL;
+	}
+}
+
+/**
  * up_backend_get_critical_action:
  * @backend: The %UpBackend class instance
  *
diff --git a/src/up-backend.h b/src/up-backend.h
index 7b3145c..213c0e1 100644
--- a/src/up-backend.h
+++ b/src/up-backend.h
@@ -69,6 +69,7 @@ void		 up_backend_test			(gpointer	 user_data);
 
 gboolean	 up_backend_coldplug			(UpBackend	*backend,
 							 UpDaemon	*daemon);
+void		 up_backend_unplug			(UpBackend	*backend);
 void		 up_backend_take_action			(UpBackend	*backend);
 const char	*up_backend_get_critical_action		(UpBackend	*backend);
 
diff --git a/src/up-daemon.c b/src/up-daemon.c
index c795c93..f857c00 100644
--- a/src/up-daemon.c
+++ b/src/up-daemon.c
@@ -547,6 +547,24 @@ out:
 }
 
 /**
+ * up_daemon_shutdown:
+ *
+ * Stop the daemon, release all devices and resources.
+ **/
+void
+up_daemon_shutdown (UpDaemon *daemon)
+{
+	/* stop accepting new devices and clear backend state */
+	up_backend_unplug (daemon->priv->backend);
+
+	/* forget about discovered devices and release UpDaemon reference */
+	up_device_list_clear (daemon->priv->power_devices, TRUE);
+
+	/* release UpDaemon reference */
+	up_device_unplug (daemon->priv->display_device);
+}
+
+/**
  * up_daemon_get_device_list:
  **/
 UpDeviceList *
diff --git a/src/up-daemon.h b/src/up-daemon.h
index 3392ad0..87857b3 100644
--- a/src/up-daemon.h
+++ b/src/up-daemon.h
@@ -72,6 +72,7 @@ guint		 up_daemon_get_number_devices_of_type (UpDaemon	*daemon,
 						 UpDeviceKind		 type);
 UpDeviceList	*up_daemon_get_device_list	(UpDaemon		*daemon);
 gboolean	 up_daemon_startup		(UpDaemon		*daemon);
+void		 up_daemon_shutdown		(UpDaemon		*daemon);
 void		 up_daemon_set_lid_is_closed	(UpDaemon		*daemon,
 						 gboolean		 lid_is_closed);
 void		 up_daemon_set_lid_is_present	(UpDaemon		*daemon,
diff --git a/src/up-device-list.c b/src/up-device-list.c
index da5555b..b95925a 100644
--- a/src/up-device-list.c
+++ b/src/up-device-list.c
@@ -130,6 +130,37 @@ up_device_list_remove (UpDeviceList *list, GObject *device)
 }
 
 /**
+ * up_device_list_remove_cb:
+ **/
+static gboolean
+up_device_list_remove_all_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	return TRUE;
+}
+
+/**
+ * up_device_list_clear:
+ * @list: This class instance
+ * @unref_it: %TRUE if you own a reference to the objects and want to drop it.
+ *
+ * Clear the contents of this list.
+ **/
+void
+up_device_list_clear (UpDeviceList *list, gboolean unref_it)
+{
+	g_return_if_fail (UP_IS_DEVICE_LIST (list));
+
+	/* caller owns these objects, but wants to destroy them */
+	if (unref_it)
+		g_ptr_array_foreach (list->priv->array, (GFunc) g_object_unref, NULL);
+
+	/* remove all devices from the db */
+	g_hash_table_foreach_remove (list->priv->map_native_path_to_device,
+				     up_device_list_remove_all_cb, NULL);
+	g_ptr_array_set_size (list->priv->array, 0);
+}
+
+/**
  * up_device_list_get_array:
  *
  * This is quick to iterate when we don't have GObject's to resolve
diff --git a/src/up-device-list.h b/src/up-device-list.h
index 709c893..85a06bb 100644
--- a/src/up-device-list.h
+++ b/src/up-device-list.h
@@ -61,6 +61,8 @@ gboolean	 up_device_list_insert			(UpDeviceList		*list,
 							 GObject		*device);
 gboolean	 up_device_list_remove			(UpDeviceList		*list,
 							 GObject		*device);
+void		 up_device_list_clear			(UpDeviceList		*list,
+							 gboolean unref_it);
 GPtrArray	*up_device_list_get_array		(UpDeviceList		*list);
 
 G_END_DECLS
diff --git a/src/up-device.c b/src/up-device.c
index 685be80..01b9f56 100644
--- a/src/up-device.c
+++ b/src/up-device.c
@@ -722,6 +722,22 @@ bail:
 }
 
 /**
+ * up_device_unplug:
+ *
+ * Initiates destruction of %UpDevice, undoing the effects of
+ * up_device_coldplug.
+ */
+void
+up_device_unplug (UpDevice *device)
+{
+	/* break circular dependency */
+	if (device->priv->daemon != NULL) {
+		g_object_unref (device->priv->daemon);
+		device->priv->daemon = NULL;
+	}
+}
+
+/**
  * up_device_register_display_device:
  **/
 gboolean
diff --git a/src/up-device.h b/src/up-device.h
index 53415e7..a2d0b7e 100644
--- a/src/up-device.h
+++ b/src/up-device.h
@@ -75,6 +75,7 @@ UpDevice	*up_device_new			(void);
 gboolean	 up_device_coldplug		(UpDevice	*device,
 						 UpDaemon	*daemon,
 						 GObject	*native);
+void		 up_device_unplug		(UpDevice	*device);
 gboolean	 up_device_register_display_device (UpDevice	*device,
 						    UpDaemon	*daemon);
 UpDaemon	*up_device_get_daemon		(UpDevice	*device);
diff --git a/src/up-main.c b/src/up-main.c
index c27cfb4..cb835b7 100644
--- a/src/up-main.c
+++ b/src/up-main.c
@@ -278,6 +278,7 @@ main (gint argc, gchar **argv)
 
 	/* wait for input or timeout */
 	g_main_loop_run (loop);
+	up_daemon_shutdown (daemon);
 	retval = 0;
 out:
 	if (kbd_backlight != NULL)
-- 
2.1.3



More information about the devkit-devel mailing list