Commit 2cf274c0 authored by Thomas Haller's avatar Thomas Haller

core: order destruction of singleton instances

Previously, the order of destructing singleton instances
was undefined. Now, have singleton instances register their
destruction via nm_singleton_instance_register().

Objects that are registered later, will be destructed earlier. IOW,
they will be destroyed in reverse order of construction.

This is only a crude method to get the lifetime of singleton instances
right by default. Having singletons ref other singletons to keep them
alive gives more control over the lifetimes of singletons. This change
of having a defined order of destruction does not conflict with taking
references to singletons (and thus extending their lifetime).

Note that previously, NMPlatform was not registered for destruction.
We don't change that yet and intenionally leak a reference.
parent e0bded93
......@@ -112,6 +112,53 @@ _nm_utils_set_testing (NMUtilsTestFlags flags)
}
}
/*****************************************************************************/
static GSList *_singletons = NULL;
static gboolean _singletons_shutdown = FALSE;
static void
_nm_singleton_instance_weak_cb (gpointer data,
GObject *where_the_object_was)
{
_singletons = g_slist_remove (_singletons, where_the_object_was);
}
static void __attribute__((destructor))
_nm_singleton_instance_destroy (void)
{
_singletons_shutdown = TRUE;
while (_singletons) {
GObject *instance = _singletons->data;
_singletons = g_slist_delete_link (_singletons, _singletons);
g_object_weak_unref (instance, _nm_singleton_instance_weak_cb, NULL);
if (instance->ref_count > 1)
nm_log_dbg (LOGD_CORE, "disown %s singleton (%p). There are more references and the instance might leak", G_OBJECT_TYPE_NAME (instance), instance);
g_object_unref (instance);
}
}
void
_nm_singleton_instance_register_destruction (GObject *instance)
{
g_return_if_fail (G_IS_OBJECT (instance));
/* Don't allow registration after shutdown. We only destroy the singletons
* once. */
g_return_if_fail (!_singletons_shutdown);
g_object_weak_ref (instance, _nm_singleton_instance_weak_cb, NULL);
_singletons = g_slist_prepend (_singletons, instance);
}
/*****************************************************************************/
/*
* nm_ethernet_address_is_valid:
* @addr: pointer to a binary or ASCII Ethernet address
......
......@@ -34,7 +34,7 @@
#define NM_DEFINE_SINGLETON_INSTANCE(TYPE) \
static TYPE *singleton_instance
#define NM_DEFINE_SINGLETON_WEAK_REF(TYPE) \
#define NM_DEFINE_SINGLETON_REGISTER(TYPE) \
NM_DEFINE_SINGLETON_INSTANCE (TYPE); \
static void \
_singleton_instance_weak_ref_cb (gpointer data, \
......@@ -44,22 +44,13 @@ _singleton_instance_weak_ref_cb (gpointer data, \
singleton_instance = NULL; \
} \
static inline void \
nm_singleton_instance_weak_ref_register (void) \
nm_singleton_instance_register () \
{ \
g_object_weak_ref (G_OBJECT (singleton_instance), _singleton_instance_weak_ref_cb, NULL); \
_nm_singleton_instance_register_destruction (G_OBJECT (singleton_instance)); \
}
#define NM_DEFINE_SINGLETON_DESTRUCTOR(TYPE) \
NM_DEFINE_SINGLETON_INSTANCE (TYPE); \
static void __attribute__((destructor)) \
_singleton_destructor (void) \
{ \
if (singleton_instance) { \
if (G_OBJECT (singleton_instance)->ref_count > 1) \
nm_log_dbg (LOGD_CORE, "disown %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \
g_object_unref (singleton_instance); \
} \
}
void _nm_singleton_instance_register_destruction (GObject *instance);
/* By default, the getter will assert that the singleton will be created only once. You can
* change this by redefining NM_DEFINE_SINGLETON_ALLOW_MULTIPLE. */
......@@ -69,7 +60,7 @@ _singleton_destructor (void) \
#define NM_DEFINE_SINGLETON_GETTER(TYPE, GETTER, GTYPE, ...) \
NM_DEFINE_SINGLETON_INSTANCE (TYPE); \
NM_DEFINE_SINGLETON_WEAK_REF (TYPE); \
NM_DEFINE_SINGLETON_REGISTER (TYPE); \
TYPE * \
GETTER (void) \
{ \
......@@ -80,12 +71,11 @@ GETTER (void) \
_already_created = TRUE;\
singleton_instance = (g_object_new (GTYPE, ##__VA_ARGS__, NULL)); \
g_assert (singleton_instance); \
nm_singleton_instance_weak_ref_register (); \
nm_singleton_instance_register (); \
nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \
} \
return singleton_instance; \
} \
NM_DEFINE_SINGLETON_DESTRUCTOR(TYPE)
}
/*****************************************************************************/
......
......@@ -440,6 +440,12 @@ main (int argc, char *argv[])
/* Set up platform interaction layer */
nm_linux_platform_setup ();
/* FIXME: intentionally leak the singleton instance of NMPlatform.
* nm_linux_platform_setup() will register the singleton for destruction,
* but we don't yet shut down all singletons properly, so don't destroy
* NMPlatform. */
g_object_ref (NM_PLATFORM_GET);
nm_auth_manager_setup (nm_config_get_auth_polkit (config));
nm_dispatcher_init ();
......
......@@ -78,8 +78,7 @@ typedef struct {
#endif
} NMAuthManagerPrivate;
NM_DEFINE_SINGLETON_DESTRUCTOR (NMAuthManager);
NM_DEFINE_SINGLETON_WEAK_REF (NMAuthManager);
NM_DEFINE_SINGLETON_REGISTER (NMAuthManager);
G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT)
......@@ -499,7 +498,7 @@ nm_auth_manager_setup (gboolean polkit_enabled)
_LOGD ("set instance");
singleton_instance = self;
nm_singleton_instance_weak_ref_register ();
nm_singleton_instance_register ();
return self;
}
......
......@@ -78,8 +78,7 @@ static void nm_bus_manager_cleanup (NMBusManager *self, gboolean dispose);
static void start_reconnection_timeout (NMBusManager *self);
static void object_destroyed (NMBusManager *self, gpointer object);
NM_DEFINE_SINGLETON_DESTRUCTOR (NMBusManager);
NM_DEFINE_SINGLETON_WEAK_REF (NMBusManager);
NM_DEFINE_SINGLETON_REGISTER (NMBusManager);
NMBusManager *
nm_bus_manager_get (void)
......@@ -103,7 +102,7 @@ nm_bus_manager_setup (NMBusManager *instance)
already_setup = TRUE;
singleton_instance = instance;
nm_singleton_instance_weak_ref_register ();
nm_singleton_instance_register ();
nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", "NMBusManager", singleton_instance);
}
......
......@@ -1671,8 +1671,7 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, int signal)
g_object_unref (old_data);
}
NM_DEFINE_SINGLETON_DESTRUCTOR (NMConfig);
NM_DEFINE_SINGLETON_WEAK_REF (NMConfig);
NM_DEFINE_SINGLETON_REGISTER (NMConfig);
NMConfig *
nm_config_get (void)
......@@ -1688,7 +1687,7 @@ nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefix
singleton_instance = nm_config_new (cli, atomic_section_prefixes, error);
if (singleton_instance)
nm_singleton_instance_weak_ref_register ();
nm_singleton_instance_register ();
return singleton_instance;
}
......
......@@ -112,7 +112,7 @@ typedef struct {
/* Singleton NMPlatform subclass instance and cached class object */
NM_DEFINE_SINGLETON_INSTANCE (NMPlatform);
NM_DEFINE_SINGLETON_WEAK_REF (NMPlatform);
NM_DEFINE_SINGLETON_REGISTER (NMPlatform);
/* Just always initialize a @klass instance. NM_PLATFORM_GET_CLASS()
* is only a plain read on the self instance, which the compiler
......@@ -154,7 +154,7 @@ nm_platform_setup (NMPlatform *instance)
singleton_instance = instance;
nm_singleton_instance_weak_ref_register ();
nm_singleton_instance_register ();
nm_log_dbg (LOGD_CORE, "setup NMPlatform singleton (%p, %s)", instance, G_OBJECT_TYPE_NAME (instance));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment