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.
This commit is contained in:
@@ -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.
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
@@ -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,
|
||||
@@ -4651,6 +4710,14 @@ nm_manager_class_init (NMManagerClass *manager_class)
|
||||
0, NM_STATE_DISCONNECTED, 0,
|
||||
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,
|
||||
|
@@ -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"
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user