From 90994b0d81ca8e44e6a150c53d2c713fad39c29c Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 20 Nov 2014 15:55:37 +0100 Subject: daemon: release resources at shutdown 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 @@ -128,6 +128,26 @@ 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->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 @@ -293,6 +293,30 @@ 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->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 @@ -149,6 +149,22 @@ 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->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 @@ -546,6 +546,24 @@ out: return ret; } +/** + * 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: **/ 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 @@ -129,6 +129,37 @@ up_device_list_remove (UpDeviceList *list, GObject *device) return TRUE; } +/** + * 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: * 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 @@ -721,6 +721,22 @@ bail: return ret; } +/** + * 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: **/ 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) -- cgit v1.2.1