diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c index 0980b9f9..7ba2cdec 100644 --- a/src/mm-base-manager.c +++ b/src/mm-base-manager.c @@ -1167,6 +1167,7 @@ mm_base_manager_cleanup (MMBaseManager *self, GHashTableIter iter; MMDevice *device; gboolean disable, remove, low_power, terse; + guint active_bearers = 0; g_return_if_fail (self != NULL); g_return_if_fail (MM_IS_BASE_MANAGER (self)); @@ -1193,7 +1194,20 @@ mm_base_manager_cleanup (MMBaseManager *self, g_hash_table_iter_init (&iter, self->priv->devices); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) { DeviceCleanupContext *dctx; - GTask *task; + GTask *task; + MMBaseModem *modem; + + modem = mm_device_peek_modem (device); + if (modem) { + guint count = 0; + + mm_iface_modem_count_bearers (MM_IFACE_MODEM (modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE, + &count, + NULL, + NULL); + active_bearers += count; + } task = g_task_new (device, NULL, @@ -1201,12 +1215,18 @@ mm_base_manager_cleanup (MMBaseManager *self, ctx); ctx->tasks = g_slist_append (ctx->tasks, task); - dctx = device_cleanup_context_new (mm_device_peek_modem (device), flags); + dctx = device_cleanup_context_new (modem, flags); g_task_set_task_data (task, dctx, (GDestroyNotify)device_cleanup_context_free); device_cleanup_step (task); } + /* Increase cleanup timeout for each connected bearer; disconnecting a + * bearer can take many seconds. + */ + if (active_bearers) + mm_sleep_context_timeout_backoff (sleep_ctx, active_bearers * 20); + /* Complete cleanup if there were no devices */ manager_cleanup_context_maybe_complete (ctx, NULL, NULL, FALSE); } diff --git a/src/mm-bearer-mbim.c b/src/mm-bearer-mbim.c index eb30f78a..d102f33b 100644 --- a/src/mm-bearer-mbim.c +++ b/src/mm-bearer-mbim.c @@ -1459,10 +1459,11 @@ load_settings_from_bearer (MMBearerMbim *self, guint max_multiplexed_bearers; const gchar *data_port_driver; - if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem), - ¤t_multiplexed_bearers, - &max_multiplexed_bearers, - error)) + if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED, + ¤t_multiplexed_bearers, + &max_multiplexed_bearers, + error)) return FALSE; /* Check multiplex support in the kernel and the device */ diff --git a/src/mm-bearer-qmi.c b/src/mm-bearer-qmi.c index 8f387ce8..64d983eb 100644 --- a/src/mm-bearer-qmi.c +++ b/src/mm-bearer-qmi.c @@ -2425,10 +2425,11 @@ load_settings_from_bearer (MMBearerQmi *self, guint max_multiplexed_bearers; gboolean multiplex_supported = TRUE; - if (!mm_broadband_modem_get_active_multiplexed_bearers (MM_BROADBAND_MODEM (ctx->modem), - ¤t_multiplexed_bearers, - &max_multiplexed_bearers, - error)) + if (!mm_iface_modem_count_bearers (MM_IFACE_MODEM (ctx->modem), + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED, + ¤t_multiplexed_bearers, + &max_multiplexed_bearers, + error)) return FALSE; /* Check multiplex support in the kernel and the device */ diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 9a83ec05..b36f4896 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -13809,52 +13809,6 @@ mm_broadband_modem_get_current_charset (MMBroadbandModem *self) /*****************************************************************************/ -static void -bearer_count_multiplexed_connected (MMBaseBearer *bearer, - guint *count) -{ - /* The Multiplexed property is only set if connected, so it's enough to check - * that one to see if we're connected and multiplexed */ - if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer))) - *count += 1; -} - -gboolean -mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self, - guint *out_current, - guint *out_max, - GError **error) -{ - g_autoptr(MMBearerList) list = NULL; - guint max; - guint count = 0; - - g_object_get (self, - MM_IFACE_MODEM_BEARER_LIST, &list, - NULL); - - if (!list) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable"); - return FALSE; - } - - max = mm_bearer_list_get_max_active_multiplexed (list); - - mm_bearer_list_foreach (list, - (MMBearerListForeachFunc)bearer_count_multiplexed_connected, - &count); - g_assert (!(!max && count)); - - if (out_max) - *out_max = max; - if (out_current) - *out_current = count; - - return TRUE; -} - -/*****************************************************************************/ - gchar * mm_broadband_modem_create_device_identifier (MMBroadbandModem *self, const gchar *ati, diff --git a/src/mm-broadband-modem.h b/src/mm-broadband-modem.h index b96e64e3..366b33dc 100644 --- a/src/mm-broadband-modem.h +++ b/src/mm-broadband-modem.h @@ -135,12 +135,6 @@ gboolean mm_broadband_modem_sim_hot_swap_ports_context_init (MMBroadbandModem GError **error); void mm_broadband_modem_sim_hot_swap_ports_context_reset (MMBroadbandModem *self); -/* Helper to manage multiplexed bearers */ -gboolean mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *self, - guint *out_current, - guint *out_max, - GError **error); - /* Helper to manage initial EPS bearer */ gint mm_broadband_modem_get_initial_eps_bearer_cid (MMBroadbandModem *self); diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index 0e14d77c..af37ca2b 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -6784,6 +6784,74 @@ mm_iface_modem_get_current_modes (MMIfaceModem *self, /*****************************************************************************/ +typedef struct { + const MMIfaceModemCountBearersFlags flags; + guint count; +} CountBearersContext; + +static void +bearer_count (MMBaseBearer *bearer, + CountBearersContext *ctx) +{ + MMBearerStatus status; + + status = mm_base_bearer_get_status (MM_BASE_BEARER (bearer)); + + if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED) { + /* The Multiplexed property is only set if connected, so it's enough to check + * that one to see if we're connected and multiplexed */ + if (mm_gdbus_bearer_get_multiplexed (MM_GDBUS_BEARER (bearer))) + ctx->count++; + } else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED) { + if (status == MM_BEARER_STATUS_CONNECTED) + ctx->count++; + } else if (ctx->flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE) { + if (status >= MM_BEARER_STATUS_CONNECTING) + ctx->count++; + } else + ctx->count++; +} + +gboolean +mm_iface_modem_count_bearers (MMIfaceModem *self, + MMIfaceModemCountBearersFlags flags, + guint *out_current, + guint *out_max, + GError **error) +{ + g_autoptr(MMBearerList) list = NULL; + guint max = 0; + CountBearersContext ctx = { + .flags = flags, + .count = 0, + }; + + g_object_get (self, + MM_IFACE_MODEM_BEARER_LIST, &list, + NULL); + if (!list) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Bearer list unavailable"); + return FALSE; + } + + if (flags & MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED) + max = mm_bearer_list_get_max_active_multiplexed (list); + else + max = mm_bearer_list_get_max_active (list); + + mm_bearer_list_foreach (list, (MMBearerListForeachFunc)bearer_count, &ctx); + g_assert (max >= ctx.count); + + if (out_max) + *out_max = max; + if (out_current) + *out_current = ctx.count; + + return TRUE; +} + +/*****************************************************************************/ + static void mm_iface_modem_default_init (MMIfaceModemInterface *iface) { diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h index 4bd6ac19..eab98d1a 100644 --- a/src/mm-iface-modem.h +++ b/src/mm-iface-modem.h @@ -622,4 +622,19 @@ void mm_iface_modem_process_sim_event (MMIfaceModem *self); gboolean mm_iface_modem_is_primary_sim_slot_switch_ongoing (MMIfaceModem *self); +typedef enum { + /* Connecting or connected bearers */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_ACTIVE = 0x1, + /* Fully connected bearers */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_CONNECTED = 0x2, + /* Multiplexed implies connected */ + MM_IFACE_MODEM_COUNT_BEARERS_FLAG_MULTIPLEXED = 0x4, +} MMIfaceModemCountBearersFlags; + +gboolean mm_iface_modem_count_bearers (MMIfaceModem *self, + MMIfaceModemCountBearersFlags flags, + guint *out_current, + guint *out_max, + GError **error); + #endif /* MM_IFACE_MODEM_H */ diff --git a/src/mm-sleep-context.c b/src/mm-sleep-context.c index 69a9da22..d6c01198 100644 --- a/src/mm-sleep-context.c +++ b/src/mm-sleep-context.c @@ -27,6 +27,7 @@ G_DEFINE_TYPE_EXTENDED (MMSleepContext, mm_sleep_context, G_TYPE_OBJECT, 0, struct _MMSleepContextPrivate { GTask *task; guint timeout_id; + gint64 timeout_start; }; enum { @@ -52,6 +53,7 @@ timeout_cleanup (MMSleepContext *self) if (self->priv->timeout_id) g_source_remove (self->priv->timeout_id); self->priv->timeout_id = 0; + self->priv->timeout_start = 0; } void @@ -95,6 +97,33 @@ operation_ready (MMSleepContext *self, g_signal_emit (self, signals[DONE], 0, error); } +static void +timeout_add (MMSleepContext *self, + guint interval) +{ + timeout_cleanup (self); + self->priv->timeout_start = g_get_monotonic_time (); + self->priv->timeout_id = g_timeout_add_seconds (interval, + (GSourceFunc)operation_timeout, + self); +} + +void +mm_sleep_context_timeout_backoff (MMSleepContext *self, + guint more_seconds) +{ + gint64 cur_time; + gint64 new_interval; + + new_interval = more_seconds * G_USEC_PER_SEC; + if (self->priv->timeout_start) { + cur_time = g_get_monotonic_time (); + new_interval += (cur_time - self->priv->timeout_start); + } + + timeout_add (self, new_interval / G_USEC_PER_SEC); +} + /*****************************************************************************/ MMSleepContext * @@ -107,9 +136,7 @@ mm_sleep_context_new (guint timeout_seconds) NULL, (GAsyncReadyCallback)operation_ready, NULL); - self->priv->timeout_id = g_timeout_add_seconds (timeout_seconds, - (GSourceFunc)operation_timeout, - self); + timeout_add (self, timeout_seconds); mm_obj_dbg (self, "new context with %d second timeout", timeout_seconds); return self; diff --git a/src/mm-sleep-context.h b/src/mm-sleep-context.h index cd45c1f2..44b3c28a 100644 --- a/src/mm-sleep-context.h +++ b/src/mm-sleep-context.h @@ -51,6 +51,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSleepContext, g_object_unref) MMSleepContext *mm_sleep_context_new (guint timeout_seconds); +void mm_sleep_context_timeout_backoff (MMSleepContext *self, + guint more_seconds); + /* The MMSleepContext assumes ownership of @error */ void mm_sleep_context_complete (MMSleepContext *self, GError *error);