From b8e7e50c805fcb7a7e2bf4aa83a01747ad6eba1f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 25 Oct 2012 14:23:50 -0500 Subject: [PATCH] olpc: ensure correct teardown of mesh device and companion wifi If the mesh device gets removed first, ensure it cleans up its signal handlers so they don't get called when the wifi device is removed. Fixes warnings on NM shutdown where the mesh device object could be used after being freed. --- src/nm-device-olpc-mesh.c | 73 ++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index 3d5b264ed4..d07f28eece 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -105,6 +105,11 @@ struct _NMDeviceOlpcMeshPrivate NMDevice * companion; gboolean stage1_waiting; guint device_added_id; + guint device_removed_id; + guint cmp_state_changed_id; + guint cmp_scanning_id; + guint cmp_scanning_allowed_id; + guint cmp_autoconnect_allowed_id; }; static void state_changed (NMDevice *device, NMDeviceState new_state, @@ -434,6 +439,38 @@ act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) return NM_ACT_STAGE_RETURN_SUCCESS; } +static void +companion_cleanup (NMDeviceOlpcMesh *self) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + if (priv->companion == NULL) + return; + + if (priv->cmp_state_changed_id) { + g_signal_handler_disconnect (priv->companion, priv->cmp_state_changed_id); + priv->cmp_state_changed_id = 0; + } + + if (priv->cmp_scanning_id) { + g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_id); + priv->cmp_scanning_id = 0; + } + + if (priv->cmp_scanning_allowed_id) { + g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_allowed_id); + priv->cmp_scanning_allowed_id = 0; + } + + if (priv->cmp_autoconnect_allowed_id) { + g_signal_handler_disconnect (priv->companion, priv->cmp_autoconnect_allowed_id); + priv->cmp_autoconnect_allowed_id = 0; + } + + priv->companion = NULL; + g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION); +} + static void dispose (GObject *object) { @@ -451,10 +488,13 @@ dispose (GObject *object) wifi_utils_deinit (priv->wifi_data); device_cleanup (self); + companion_cleanup (self); manager = nm_manager_get (); if (priv->device_added_id) g_signal_handler_disconnect (manager, priv->device_added_id); + if (priv->device_removed_id) + g_signal_handler_disconnect (manager, priv->device_removed_id); g_object_unref (manager); G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); @@ -645,7 +685,6 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other) return FALSE; } - /* FIXME detect when our companion leaves */ priv->companion = other; /* When we've found the companion, stop listening for other devices */ @@ -664,14 +703,17 @@ is_companion (NMDeviceOlpcMesh *self, NMDevice *other) nm_device_get_iface (NM_DEVICE (self)), nm_device_get_iface (other)); - g_signal_connect (G_OBJECT (other), "state-changed", - G_CALLBACK (companion_state_changed_cb), self); - g_signal_connect (G_OBJECT (other), "notify::scanning", - G_CALLBACK (companion_notify_cb), self); - g_signal_connect (G_OBJECT (other), "scanning-allowed", - G_CALLBACK (companion_scan_allowed_cb), self); - g_signal_connect (G_OBJECT (other), "autoconnect-allowed", - G_CALLBACK (companion_autoconnect_allowed_cb), self); + priv->cmp_state_changed_id = g_signal_connect (G_OBJECT (other), "state-changed", + G_CALLBACK (companion_state_changed_cb), self); + + priv->cmp_scanning_id = g_signal_connect (G_OBJECT (other), "notify::scanning", + G_CALLBACK (companion_notify_cb), self); + + priv->cmp_scanning_allowed_id = g_signal_connect (G_OBJECT (other), "scanning-allowed", + G_CALLBACK (companion_scan_allowed_cb), self); + + priv->cmp_autoconnect_allowed_id = g_signal_connect (G_OBJECT (other), "autoconnect-allowed", + G_CALLBACK (companion_autoconnect_allowed_cb), self); g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION); @@ -686,6 +728,15 @@ device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) is_companion (self, other); } +static void +device_removed_cb (NMManager *manager, NMDevice *other, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + + if (other == NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->companion) + companion_cleanup (self); +} + static gboolean check_companion_cb (gpointer user_data) { @@ -708,6 +759,10 @@ check_companion_cb (gpointer user_data) priv->device_added_id = g_signal_connect (manager, "device-added", G_CALLBACK (device_added_cb), self); + if (!priv->device_removed_id) { + priv->device_removed_id = g_signal_connect (manager, "device-removed", + G_CALLBACK (device_removed_cb), self); + } /* Try to find the companion if it's already known to the NMManager */ for (list = nm_manager_get_devices (manager); list ; list = g_slist_next (list)) {