summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-03-15 10:40:17 +0100
committerThomas Haller <thaller@redhat.com>2017-03-15 10:40:17 +0100
commit7cb3928c499c0a5a7d70a03c93256540dea47321 (patch)
tree9a8302c7617cb056c9e49e450d28cde9224b2389
parent22b7282d843f24442aed6a72617e0038f572b2c9 (diff)
parentc8934fbe0df0459508a47dfd33b35e9e27dbc77b (diff)
downloadNetworkManager-7cb3928c499c0a5a7d70a03c93256540dea47321.tar.gz
core: merge branch 'th/startup-complete-race-bgo779920'
https://bugzilla.gnome.org/show_bug.cgi?id=779920
-rw-r--r--src/devices/nm-device.c46
-rw-r--r--src/main.c2
-rw-r--r--src/nm-manager.c70
3 files changed, 85 insertions, 33 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index cfa91951a0..5857b8f84c 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -10645,6 +10645,8 @@ _set_unmanaged_flags (NMDevice *self,
const char *operation = NULL;
char str1[512];
char str2[512];
+ gboolean do_notify_has_pending_actions = FALSE;
+ gboolean had_pending_actions = FALSE;
g_return_if_fail (NM_IS_DEVICE (self));
g_return_if_fail (flags);
@@ -10680,6 +10682,11 @@ _set_unmanaged_flags (NMDevice *self,
nm_assert_se (!nm_clear_g_source (&priv->queued_ip6_config_id));
priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self);
}
+
+ if (!priv->pending_actions) {
+ do_notify_has_pending_actions = TRUE;
+ had_pending_actions = nm_device_has_pending_action (self);
+ }
}
old_flags = priv->unmanaged_flags;
@@ -10715,19 +10722,16 @@ _set_unmanaged_flags (NMDevice *self,
|| ( !was_managed
&& nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED));
-#define _FMTX "[%s%s0x%0x/0x%x/%s"
-#define _FMT(flags, mask, str) \
- _unmanaged_flags2str ((flags), (mask), str, sizeof (str)), \
- ((flags) | (mask)) ? "=" : "", \
- (flags), \
- (mask), \
- (_get_managed_by_flags (flags, mask, FALSE) \
- ? "managed" \
- : (_get_managed_by_flags (flags, mask, TRUE) \
- ? "manageable" \
- : "unmanaged"))
- _LOGD (LOGD_DEVICE, "unmanaged: flags set to "_FMTX"%s, %s [%s=0x%0x]%s%s%s)",
- _FMT (priv->unmanaged_flags, priv->unmanaged_mask, str1),
+ _LOGD (LOGD_DEVICE, "unmanaged: flags set to [%s%s0x%0x/0x%x/%s%s], %s [%s=0x%0x]%s%s%s)",
+ _unmanaged_flags2str (priv->unmanaged_flags, priv->unmanaged_mask, str1, sizeof (str1)), \
+ (priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "", \
+ (guint) priv->unmanaged_flags, \
+ (guint) priv->unmanaged_mask, \
+ (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, FALSE) \
+ ? "managed" \
+ : (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, TRUE) \
+ ? "manageable" \
+ : "unmanaged")),
priv->real ? "" : "/unrealized",
operation,
nm_unmanaged_flags2str (flags, str2, sizeof (str2)),
@@ -10737,7 +10741,10 @@ _set_unmanaged_flags (NMDevice *self,
reason_to_string (reason),
transition_state ? ", transition-state" : "",
""));
-#undef _FMT
+
+ if ( do_notify_has_pending_actions
+ && had_pending_actions != nm_device_has_pending_action (self))
+ _notify (self, PROP_HAS_PENDING_ACTION);
if (transition_state) {
new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE;
@@ -11412,7 +11419,16 @@ nm_device_has_pending_action (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- return !!priv->pending_actions;
+ if (priv->pending_actions)
+ return TRUE;
+
+ if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+ /* as long as the platform link is not yet initialized, we have a pending
+ * action. */
+ return TRUE;
+ }
+
+ return FALSE;
}
/*****************************************************************************/
diff --git a/src/main.c b/src/main.c
index 157bec2093..23c05f2952 100644
--- a/src/main.c
+++ b/src/main.c
@@ -402,6 +402,8 @@ main (int argc, char *argv[])
goto done;
}
+ nm_platform_process_events (NM_PLATFORM_GET);
+
/* Make sure the loopback interface is up. If interface is down, we bring
* it up and kernel will assign it link-local IPv4 and IPv6 addresses. If
* it was already up, we assume is in clean state.
diff --git a/src/nm-manager.c b/src/nm-manager.c
index df7b8eb33a..5b9b144891 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -86,6 +86,10 @@ static void device_sleep_cb (NMDevice *device,
GParamSpec *pspec,
NMManager *self);
+static void settings_startup_complete_changed (NMSettings *settings,
+ GParamSpec *pspec,
+ NMManager *self);
+
static NM_CACHED_QUARK_FCN ("active-connection-add-and-activate", active_connection_add_and_activate_quark)
typedef struct {
@@ -129,9 +133,6 @@ typedef struct {
char *hostname;
RadioState radio_states[RFKILL_TYPE_MAX];
- gboolean sleeping;
- gboolean net_enabled;
-
NMVpnManager *vpn_manager;
NMSleepMonitor *sleep_monitor;
@@ -147,8 +148,14 @@ typedef struct {
guint timestamp_update_id;
- gboolean startup;
- gboolean devices_inited;
+ guint devices_inited_id;
+
+ bool startup:1;
+ bool devices_inited:1;
+ bool devices_inited_ready:1;
+
+ bool sleeping:1;
+ bool net_enabled:1;
} NMManagerPrivate;
struct _NMManager {
@@ -937,15 +944,18 @@ check_if_startup_complete (NMManager *self)
_LOGI (LOGD_CORE, "startup complete");
priv->startup = FALSE;
- _notify (self, PROP_STARTUP);
- /* We don't have to watch notify::has-pending-action any more. */
+ /* we no longer care about these signals. Startup-complete only
+ * happens once. */
+ g_signal_handlers_disconnect_by_func (priv->settings, G_CALLBACK (settings_startup_complete_changed), self);
for (iter = priv->devices; iter; iter = iter->next) {
- NMDevice *dev = iter->data;
-
- g_signal_handlers_disconnect_by_func (dev, G_CALLBACK (device_has_pending_action_changed), self);
+ g_signal_handlers_disconnect_by_func (iter->data,
+ G_CALLBACK (device_has_pending_action_changed),
+ self);
}
+ _notify (self, PROP_STARTUP);
+
if (nm_config_get_configure_and_quit (priv->config))
g_signal_emit (self, signals[CONFIGURE_QUIT], 0);
}
@@ -4804,6 +4814,25 @@ nm_manager_write_device_state (NMManager *self)
seen_ifindexes);
}
+static gboolean
+devices_inited_cb (gpointer user_data)
+{
+ NMManager *self = user_data;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+ if (!priv->devices_inited_ready) {
+ /* lets go through another idle invocation to give the system
+ * more time to settle. */
+ priv->devices_inited_ready = TRUE;
+ return G_SOURCE_CONTINUE;
+ }
+
+ priv->devices_inited_id = 0;
+ priv->devices_inited = TRUE;
+ check_if_startup_complete (self);
+ return G_SOURCE_REMOVE;
+}
+
gboolean
nm_manager_start (NMManager *self, GError **error)
{
@@ -4814,11 +4843,6 @@ nm_manager_start (NMManager *self, GError **error)
if (!nm_settings_start (priv->settings, error))
return FALSE;
- g_signal_connect (NM_PLATFORM_GET,
- NM_PLATFORM_SIGNAL_LINK_CHANGED,
- G_CALLBACK (platform_link_cb),
- self);
-
/* Set initial radio enabled/disabled state */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
@@ -4851,6 +4875,13 @@ nm_manager_start (NMManager *self, GError **error)
nm_device_factory_manager_load_factories (_register_device_factory, self);
nm_device_factory_manager_for_each_factory (start_factory, NULL);
+ nm_platform_process_events (NM_PLATFORM_GET);
+
+ g_signal_connect (NM_PLATFORM_GET,
+ NM_PLATFORM_SIGNAL_LINK_CHANGED,
+ G_CALLBACK (platform_link_cb),
+ self);
+
platform_query_devices (self);
/* Load VPN plugins */
@@ -4864,9 +4895,8 @@ nm_manager_start (NMManager *self, GError **error)
for (i = 0; connections[i]; i++)
connection_changed (self, NM_CONNECTION (connections[i]));
- priv->devices_inited = TRUE;
-
- check_if_startup_complete (self);
+ nm_clear_g_source (&priv->devices_inited_id);
+ priv->devices_inited_id = g_idle_add_full (G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL);
return TRUE;
}
@@ -4881,6 +4911,8 @@ nm_manager_stop (NMManager *self)
remove_device (self, NM_DEVICE (priv->devices->data), TRUE, TRUE);
_active_connection_cleanup (self);
+
+ nm_clear_g_source (&priv->devices_inited_id);
}
static gboolean
@@ -6039,6 +6071,8 @@ dispose (GObject *object)
g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref);
priv->auth_chains = NULL;
+ nm_clear_g_source (&priv->devices_inited_id);
+
if (priv->checkpoint_mgr) {
nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL);
g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref);