core: fix dbus-glib crash on shutdown with systemd

It's really dbus-glib's fault, but the problem seems to be that when
short-lived D-Bus calls are made (with dbus_g_proxy_call_no_reply)
and the service is activated, then quits immediately like the
dispatcher does, there's not enough time for internal dbus-glib
housekeeping.  The GetNameOwner call that's kicked off when the
DBusGProxy is created hasn't returned by the time the proxy is
being unrefed, so the proxy doesn't end up on the
unassociated_proxies list.  But when the proxy is destroyed, and
it destroys it's DBusGProxyManager, the manager expects that
the proxy is on unassociated_proxies.  Thus the crash.

I'm not entirely sure why we hit this only at shutdown with
systemd; it could be that systemd is killing the bus daemon at
the same time as we're running the dispatcher and that's why the
GetNameOwner call doesn't complete.

Work around all this by expecting a message return, which works fine
during normal operation, but on shutdown allows us to avoid urefing
the proxy until everything in dbus-glib has been handled, which at
shutdown time really just means leaking it.  But then we exit, so
it's cleaned up anyway.
This commit is contained in:
Dan Williams
2011-02-21 17:03:09 -06:00
parent 106afbae50
commit b712274e86

View File

@@ -373,6 +373,13 @@ nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting)
nm_ip6_config_set_never_default (ip6_config, TRUE);
}
static void
dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
{
dbus_g_proxy_end_call (proxy, call, NULL, G_TYPE_INVALID);
g_object_unref (proxy);
}
void
nm_utils_call_dispatcher (const char *action,
NMConnection *connection,
@@ -440,18 +447,25 @@ nm_utils_call_dispatcher (const char *action,
value_hash_add_object_path (device_props, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device));
}
dbus_g_proxy_call_no_reply (proxy, "Action",
G_TYPE_STRING, action,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash,
DBUS_TYPE_G_MAP_OF_VARIANT, connection_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_props,
G_TYPE_INVALID);
g_object_unref (proxy);
/* Do a non-blocking call, but wait for the reply, because dbus-glib
* sometimes needs time to complete internal housekeeping. If we use
* dbus_g_proxy_call_no_reply(), that housekeeping (specifically the
* GetNameOwner response) doesn't complete and we run into an assert
* on unreffing the proxy.
*/
dbus_g_proxy_begin_call_with_timeout (proxy, "Action",
dispatcher_done_cb,
dbus_mgr,
g_object_unref,
5000,
G_TYPE_STRING, action,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash,
DBUS_TYPE_G_MAP_OF_VARIANT, connection_props,
DBUS_TYPE_G_MAP_OF_VARIANT, device_props,
G_TYPE_INVALID);
g_hash_table_destroy (connection_hash);
g_hash_table_destroy (connection_props);
g_hash_table_destroy (device_props);
g_object_unref (dbus_mgr);
}
gboolean