Commit bc091f2f authored by Dan Winship's avatar Dan Winship

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.
parent cee676e7
......@@ -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;
}
......
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