diff options
author | Dan Winship <danw@gnome.org> | 2013-08-13 17:45:34 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-08-16 17:27:34 -0400 |
commit | bc091f2f3ea2ee27d012f2332c514516fd61441b (patch) | |
tree | 8fb8b00a6b51203564185ae674518cea99887f5b | |
parent | cee676e7048313af32a31b18846f522fff3ec5d5 (diff) | |
download | NetworkManager-bc091f2f3ea2ee27d012f2332c514516fd61441b.tar.gz |
core: add NMManager:startup property
Add a property on NMManager indicating that it is currently starting
up and activating startup-time/boot-time network connections.
"startup" is initially TRUE, and becomes FALSE once all NMDevices
report that they have no pending activity (eg, trying to activate,
waiting for a wifi scan to complete, etc). This is tracked via a new
NMDevice:has-pending-activity property, which is maintained partially
by the device itself, and partially by other parts of the code.
-rw-r--r-- | introspection/nm-manager.xml | 8 | ||||
-rw-r--r-- | src/devices/nm-device-olpc-mesh.c | 7 | ||||
-rw-r--r-- | src/devices/nm-device-wifi.c | 21 | ||||
-rw-r--r-- | src/devices/nm-device.c | 65 | ||||
-rw-r--r-- | src/devices/nm-device.h | 5 | ||||
-rw-r--r-- | src/nm-manager.c | 71 | ||||
-rw-r--r-- | src/nm-manager.h | 1 | ||||
-rw-r--r-- | src/nm-policy.c | 5 |
8 files changed, 179 insertions, 4 deletions
diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index 6f3c8cac6a..d9f6a7c3d2 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -302,6 +302,14 @@ </tp:docstring> </property> + <property name="Startup" type="b" access="read"> + <tp:docstring> + Indicates whether NM is still starting up; this becomes FALSE + when NM has finished attempting to activate every connection + that it might be able to activate at startup. + </tp:docstring> + </property> + <property name="Version" type="s" access="read"> <tp:docstring> NetworkManager version. diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c index 4a5c5f949a..8a032e45f0 100644 --- a/src/devices/nm-device-olpc-mesh.c +++ b/src/devices/nm-device-olpc-mesh.c @@ -606,11 +606,11 @@ check_companion_cb (gpointer user_data) nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); - return FALSE; + goto done; } if (priv->device_added_id != 0) - return FALSE; + goto done; manager = nm_manager_get (); @@ -629,6 +629,8 @@ check_companion_cb (gpointer user_data) g_object_unref (manager); + done: + nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion"); return FALSE; } @@ -646,6 +648,7 @@ state_changed (NMDevice *device, NMDeviceState new_state, * transition to DISCONNECTED otherwise wait for our companion. */ g_idle_add (check_companion_cb, self); + nm_device_add_pending_action (device, "waiting for companion"); break; case NM_DEVICE_STATE_ACTIVATED: break; diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c index cad045e6a5..cffc2c2939 100644 --- a/src/devices/nm-device-wifi.c +++ b/src/devices/nm-device-wifi.c @@ -139,6 +139,7 @@ struct _NMDeviceWifiPrivate { guint8 scan_interval; /* seconds */ guint pending_scan_id; guint scanlist_cull_id; + gboolean requested_scan; Supplicant supplicant; WifiData * wifi_data; @@ -349,6 +350,9 @@ supplicant_interface_acquire (NMDeviceWifi *self) return FALSE; } + if (nm_supplicant_interface_get_state (priv->supplicant.iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + nm_device_add_pending_action (NM_DEVICE (self), "waiting for supplicant"); + g_signal_connect (priv->supplicant.iface, NM_SUPPLICANT_INTERFACE_STATE, G_CALLBACK (supplicant_iface_state_cb), @@ -1652,6 +1656,11 @@ request_wireless_scan (gpointer user_data) gboolean backoff = FALSE; GPtrArray *ssids = NULL; + if (priv->requested_scan) { + /* There's already a scan in progress */ + return FALSE; + } + if (check_scanning_allowed (self)) { nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scanning requested", nm_device_get_iface (NM_DEVICE (self))); @@ -1679,6 +1688,8 @@ request_wireless_scan (gpointer user_data) if (nm_supplicant_interface_request_scan (priv->supplicant.iface, ssids)) { /* success */ backoff = TRUE; + priv->requested_scan = TRUE; + nm_device_add_pending_action (NM_DEVICE (self), "scan"); } if (ssids) { @@ -1764,6 +1775,8 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, gboolean success, NMDeviceWifi *self) { + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan %s", nm_device_get_iface (NM_DEVICE (self)), success ? "successful" : "failed"); @@ -1774,6 +1787,11 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, * happens when there are new BSSes. */ schedule_scanlist_cull (self); + + if (priv->requested_scan) { + priv->requested_scan = FALSE; + nm_device_remove_pending_action (NM_DEVICE (self), "scan"); + } } @@ -2321,6 +2339,9 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, /* Request a scan to get latest results */ cancel_pending_scan (self); request_wireless_scan (self); + + if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) + nm_device_remove_pending_action (device, "waiting for supplicant"); break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: remove_supplicant_interface_error_handler (self); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 14ca2e1aab..a4c3ba2fea 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -130,6 +130,7 @@ enum { PROP_AVAILABLE_CONNECTIONS, PROP_IS_MASTER, PROP_HW_ADDRESS, + PROP_HAS_PENDING_ACTION, LAST_PROP }; @@ -180,6 +181,7 @@ typedef struct { NMDeviceStateReason state_reason; QueuedState queued_state; guint queued_ip_config_id; + guint pending_actions; char * udi; char * path; @@ -5180,6 +5182,9 @@ get_property (GObject *object, guint prop_id, else g_value_set_string (value, NULL); break; + case PROP_HAS_PENDING_ACTION: + g_value_set_boolean (value, nm_device_has_pending_action (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -5440,6 +5445,14 @@ nm_device_class_init (NMDeviceClass *klass) NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property + (object_class, PROP_HAS_PENDING_ACTION, + g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION, + "Has pending action", + "Has pending action", + FALSE, + G_PARAM_READABLE)); + /* Signals */ signals[STATE_CHANGED] = g_signal_new ("state-changed", @@ -5666,6 +5679,13 @@ reason_to_string (NMDeviceStateReason reason) return "unknown"; } +static inline gboolean +state_implies_pending_action (NMDeviceState state) +{ + return ( state >= NM_DEVICE_STATE_PREPARE + && state < NM_DEVICE_STATE_ACTIVATED); +} + void nm_device_state_changed (NMDevice *device, NMDeviceState state, @@ -5697,6 +5717,10 @@ nm_device_state_changed (NMDevice *device, priv->state = state; priv->state_reason = reason; + if ( state_implies_pending_action (state) + && !state_implies_pending_action (old_state)) + nm_device_add_pending_action (device, "activation"); + nm_log_info (LOGD_DEVICE, "(%s): device state change: %s -> %s (reason '%s') [%d %d %d]", nm_device_get_iface (device), state_to_string (old_state), @@ -5838,6 +5862,10 @@ nm_device_state_changed (NMDevice *device, if (req) g_object_unref (req); + if ( state_implies_pending_action (old_state) + && !state_implies_pending_action (state)) + nm_device_remove_pending_action (device, "activation"); + priv->in_state_changed = FALSE; } @@ -5864,6 +5892,7 @@ queued_set_state (gpointer user_data) nm_device_queued_state_clear (self); nm_device_state_changed (self, new_state, new_reason); + nm_device_remove_pending_action (self, "queued state change"); } else { g_warn_if_fail (priv->queued_state.state == NM_DEVICE_STATE_UNKNOWN); g_warn_if_fail (priv->queued_state.reason == NM_DEVICE_STATE_REASON_NONE); @@ -5896,6 +5925,7 @@ nm_device_queue_state (NMDevice *self, priv->queued_state.state = state; priv->queued_state.reason = reason; priv->queued_state.id = g_idle_add (queued_set_state, self); + nm_device_add_pending_action (self, "queued state change"); nm_log_dbg (LOGD_DEVICE, "(%s): queued state change to %s due to %s (id %d)", nm_device_get_iface (self), state_to_string (state), reason_to_string (reason), @@ -5923,6 +5953,7 @@ nm_device_queued_state_clear (NMDevice *self) nm_log_dbg (LOGD_DEVICE, "(%s): clearing queued state transition (id %d)", nm_device_get_iface (self), priv->queued_state.id); g_source_remove (priv->queued_state.id); + nm_device_remove_pending_action (self, "queued state change"); } memset (&priv->queued_state, 0, sizeof (priv->queued_state)); } @@ -6515,3 +6546,37 @@ nm_device_update_hw_address (NMDevice *dev) return changed; } + +void +nm_device_add_pending_action (NMDevice *device, const char *action) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + priv->pending_actions++; + nm_log_dbg (LOGD_DEVICE, "(%s): add_pending_action (%d): %s", + nm_device_get_iface (device), priv->pending_actions, action); + + if (priv->pending_actions == 1) + g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION); +} + +void +nm_device_remove_pending_action (NMDevice *device, const char *action) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + priv->pending_actions--; + nm_log_dbg (LOGD_DEVICE, "(%s): remove_pending_action (%d): %s", + nm_device_get_iface (device), priv->pending_actions, action); + + if (priv->pending_actions == 0) + g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION); +} + +gboolean +nm_device_has_pending_action (NMDevice *device) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + return priv->pending_actions > 0; +} diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 9815d2d407..e3ac2ab659 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -65,6 +65,7 @@ #define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ #define NM_DEVICE_IS_MASTER "is-master" /* Internal only */ #define NM_DEVICE_HW_ADDRESS "hw-address" /* Internal only */ +#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ #define NM_DEVICE_AUTH_REQUEST "auth-request" @@ -315,6 +316,10 @@ void nm_device_set_connection_provider (NMDevice *device, NMConnectionProvider * gboolean nm_device_supports_vlans (NMDevice *device); +void nm_device_add_pending_action (NMDevice *device, const char *action); +void nm_device_remove_pending_action (NMDevice *device, const char *action); +gboolean nm_device_has_pending_action (NMDevice *device); + G_END_DECLS /* For testing only */ diff --git a/src/nm-manager.c b/src/nm-manager.c index d12db94aaf..2ed174e38e 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -258,6 +258,7 @@ typedef struct { GHashTable *nm_bridges; + gboolean startup; gboolean disposed; } NMManagerPrivate; @@ -285,6 +286,7 @@ enum { PROP_0, PROP_VERSION, PROP_STATE, + PROP_STARTUP, PROP_NETWORKING_ENABLED, PROP_WIRELESS_ENABLED, PROP_WIRELESS_HARDWARE_ENABLED, @@ -582,9 +584,7 @@ manager_device_state_changed (NMDevice *device, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); -#if WITH_CONCHECK NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); -#endif switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: @@ -618,6 +618,50 @@ manager_device_state_changed (NMDevice *device, #endif } +static void device_has_pending_action_changed (NMDevice *device, + GParamSpec *pspec, + NMManager *self); + +static void +check_if_startup_complete (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GSList *iter; + + if (!priv->startup) + return; + + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *dev = iter->data; + + if (nm_device_has_pending_action (dev)) { + nm_log_dbg (LOGD_CORE, "check_if_startup_complete returns FALSE because of %s", + nm_device_get_iface (dev)); + return; + } + } + + nm_log_info (LOGD_CORE, "startup complete"); + + priv->startup = FALSE; + g_object_notify (G_OBJECT (self), "startup"); + + /* We don't have to watch notify::has-pending-action any more. */ + 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); + } +} + +static void +device_has_pending_action_changed (NMDevice *device, + GParamSpec *pspec, + NMManager *self) +{ + check_if_startup_complete (self); +} + static void remove_device (NMManager *manager, NMDevice *device, gboolean quitting) { @@ -645,6 +689,9 @@ remove_device (NMManager *manager, NMDevice *device, gboolean quitting) g_object_unref (device); priv->devices = g_slist_remove (priv->devices, device); + + if (priv->startup) + check_if_startup_complete (manager); } static void @@ -1933,6 +1980,12 @@ add_device (NMManager *self, NMDevice *device) G_CALLBACK (device_auth_request_cb), self); + if (priv->startup) { + g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, + G_CALLBACK (device_has_pending_action_changed), + self); + } + if (devtype == NM_DEVICE_TYPE_WIFI) { /* Attach to the access-point-added signal so that the manager can fill * non-SSID-broadcasting APs with an SSID. @@ -3824,6 +3877,8 @@ nm_manager_start (NMManager *self) /* FIXME: remove when we handle bridges non-destructively */ g_hash_table_unref (priv->nm_bridges); priv->nm_bridges = NULL; + + check_if_startup_complete (self); } static gboolean @@ -4431,6 +4486,9 @@ get_property (GObject *object, guint prop_id, nm_manager_update_state (self); g_value_set_uint (value, priv->state); break; + case PROP_STARTUP: + g_value_set_boolean (value, priv->startup); + break; case PROP_NETWORKING_ENABLED: g_value_set_boolean (value, priv->net_enabled); break; @@ -4548,6 +4606,7 @@ nm_manager_init (NMManager *manager) priv->sleeping = FALSE; priv->state = NM_STATE_DISCONNECTED; + priv->startup = TRUE; priv->dbus_mgr = nm_dbus_manager_get (); priv->dbus_connection_changed_id = g_signal_connect (priv->dbus_mgr, @@ -4652,6 +4711,14 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_READABLE)); g_object_class_install_property + (object_class, PROP_STARTUP, + g_param_spec_boolean (NM_MANAGER_STARTUP, + "Startup", + "Is NetworkManager still starting up", + TRUE, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_NETWORKING_ENABLED, g_param_spec_boolean (NM_MANAGER_NETWORKING_ENABLED, "NetworkingEnabled", diff --git a/src/nm-manager.h b/src/nm-manager.h index 5aeeaab62a..6e376787e1 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -51,6 +51,7 @@ typedef enum { #define NM_MANAGER_VERSION "version" #define NM_MANAGER_STATE "state" +#define NM_MANAGER_STARTUP "startup" #define NM_MANAGER_NETWORKING_ENABLED "networking-enabled" #define NM_MANAGER_WIRELESS_ENABLED "wireless-enabled" #define NM_MANAGER_WIRELESS_HARDWARE_ENABLED "wireless-hardware-enabled" diff --git a/src/nm-policy.c b/src/nm-policy.c index 525fbc7741..cf94033537 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -860,6 +860,8 @@ typedef struct { static void activate_data_free (ActivateData *data) { + nm_device_remove_pending_action (data->device, "autoactivate"); + if (data->id) g_source_remove (data->id); g_object_unref (data->device); @@ -958,6 +960,9 @@ activate_data_new (NMPolicy *policy, NMDevice *device, guint delay_seconds) data->id = g_timeout_add_seconds (delay_seconds, auto_activate_device, data); else data->id = g_idle_add (auto_activate_device, data); + + nm_device_add_pending_action (device, "autoactivate"); + return data; } |