pmaports/temp/modemmanager/0001-base-manager-add-quick-suspend-resume-base.patch

489 lines
16 KiB
Diff
Raw Normal View History

From d5f3a6d441f47836698b851d6049bf738d066ef6 Mon Sep 17 00:00:00 2001
From: Dylan Van Assche <me@dylanvanassche.be>
Date: Sat, 1 May 2021 15:50:47 +0200
Subject: [PATCH 01/39] base-manager: add quick suspend/resume base
Quick suspend/resume infrastructure for
synchronizing the interfaces when resuming.
---
src/main.c | 14 +++-
src/mm-base-manager.c | 48 ++++++++++++
src/mm-base-manager.h | 4 +
src/mm-base-modem.c | 155 +++++++++++++++++++++++++++++++++++++++
src/mm-base-modem.h | 23 ++++++
src/mm-broadband-modem.c | 81 ++++++++++++++++++++
src/mm-context.c | 11 +++
src/mm-context.h | 1 +
8 files changed, 336 insertions(+), 1 deletion(-)
diff --git a/src/main.c b/src/main.c
index 928078a3..4a036971 100644
--- a/src/main.c
+++ b/src/main.c
@@ -72,6 +72,13 @@ resuming_cb (MMSleepMonitor *sleep_monitor)
mm_base_manager_start (manager, FALSE);
}
+static void
+resuming_quick_cb (MMSleepMonitor *sleep_monitor)
+{
+ mm_dbg ("syncing modem state (quick resuming)");
+ mm_base_manager_sync (manager);
+}
+
#endif
static void
@@ -197,7 +204,12 @@ main (int argc, char *argv[])
if (mm_context_get_test_no_suspend_resume())
mm_dbg ("Suspend/resume support disabled at runtime");
- else {
+ else if (mm_context_get_test_quick_suspend_resume()) {
+ mm_dbg ("Quick suspend/resume hooks enabled");
+ sleep_monitor = mm_sleep_monitor_get ();
+ g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_quick_cb), NULL);
+ } else {
+ mm_dbg ("Full suspend/resume hooks enabled");
sleep_monitor = mm_sleep_monitor_get ();
g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_SLEEPING, G_CALLBACK (sleeping_cb), NULL);
g_signal_connect (sleep_monitor, MM_SLEEP_MONITOR_RESUMING, G_CALLBACK (resuming_cb), NULL);
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
index 130e5ad1..0c393f11 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -45,6 +45,7 @@
#include "mm-plugin.h"
#include "mm-filter.h"
#include "mm-log-object.h"
+#include "mm-base-modem.h"
static void initable_iface_init (GInitableIface *iface);
static void log_object_iface_init (MMLogObjectInterface *iface);
@@ -663,6 +664,53 @@ mm_base_manager_num_modems (MMBaseManager *self)
return n;
}
+/*****************************************************************************/
+/* Quick resume synchronization */
+
+#if defined WITH_SYSTEMD_SUSPEND_RESUME
+
+gboolean mm_base_modem_sync_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+mm_base_modem_sync_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ g_autoptr(GError) error;
+
+ mm_base_modem_sync_finish (self, res, &error);
+ if (error) {
+ mm_obj_warn (self, "synchronization failed");
+ return;
+ }
+ mm_obj_info (self, "synchronization finished");
+}
+
+void
+mm_base_manager_sync (MMBaseManager *self)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (MM_IS_BASE_MANAGER (self));
+
+ /* Refresh each device */
+ g_hash_table_iter_init (&iter, self->priv->devices);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ MMBaseModem *modem = mm_device_peek_modem (MM_DEVICE (value));
+ /* We just want to start the synchronization, we don't need the result */
+ mm_base_modem_sync (modem, (GAsyncReadyCallback)mm_base_modem_sync_ready, NULL);
+ }
+}
+
+#endif
+
/*****************************************************************************/
/* Set logging */
diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h
index d70fa08f..be51d0c0 100644
--- a/src/mm-base-manager.h
+++ b/src/mm-base-manager.h
@@ -66,6 +66,10 @@ void mm_base_manager_start (MMBaseManager *manager,
void mm_base_manager_shutdown (MMBaseManager *manager,
gboolean disable);
+#if defined WITH_SYSTEMD_SUSPEND_RESUME
+void mm_base_manager_sync (MMBaseManager *manager);
+#endif
+
guint32 mm_base_manager_num_modems (MMBaseManager *manager);
#endif /* MM_BASE_MANAGER_H */
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 926d0712..38f43f8c 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -369,6 +369,161 @@ mm_base_modem_grab_port (MMBaseModem *self,
return TRUE;
}
+/******************************************************************************/
+
+typedef struct {
+ gchar *name;
+ gulong link_port_grabbed_id;
+ guint timeout_id;
+} WaitLinkPortContext;
+
+static void
+wait_link_port_context_free (WaitLinkPortContext *ctx)
+{
+ g_assert (!ctx->link_port_grabbed_id);
+ g_assert (!ctx->timeout_id);
+ g_free (ctx->name);
+ g_slice_free (WaitLinkPortContext, ctx);
+}
+
+MMPort *
+mm_base_modem_wait_link_port_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (res), error);
+}
+
+static gboolean
+wait_link_port_timeout_cb (GTask *task)
+{
+ WaitLinkPortContext *ctx;
+ MMBaseModem *self;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ ctx->timeout_id = 0;
+ g_signal_handler_disconnect (self, ctx->link_port_grabbed_id);
+ ctx->link_port_grabbed_id = 0;
+
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND,
+ "Timed out waiting for link port 'net/%s'",
+ ctx->name);
+ g_object_unref (task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+wait_link_port_grabbed_cb (MMBaseModem *self,
+ MMPort *link_port,
+ GTask *task)
+{
+ WaitLinkPortContext *ctx;
+ MMPortSubsys link_port_subsystem;
+ const gchar *link_port_name;
+
+ ctx = g_task_get_task_data (task);
+
+ link_port_subsystem = mm_port_get_subsys (link_port);
+ link_port_name = mm_port_get_device (link_port);
+
+ if (link_port_subsystem != MM_PORT_SUBSYS_NET) {
+ mm_obj_warn (self, "unexpected link port subsystem grabbed: %s/%s",
+ mm_port_subsys_get_string (link_port_subsystem),
+ link_port_name);
+ return;
+ }
+
+ if (g_strcmp0 (link_port_name, ctx->name) != 0)
+ return;
+
+ /* we got it! */
+
+ g_source_remove (ctx->timeout_id);
+ ctx->timeout_id = 0;
+ g_signal_handler_disconnect (self, ctx->link_port_grabbed_id);
+ ctx->link_port_grabbed_id = 0;
+
+ g_task_return_pointer (task, g_object_ref (link_port), g_object_unref);
+ g_object_unref (task);
+}
+
+void
+mm_base_modem_wait_link_port (MMBaseModem *self,
+ const gchar *subsystem,
+ const gchar *name,
+ guint timeout_ms,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ WaitLinkPortContext *ctx;
+ GTask *task;
+ g_autofree gchar *key = NULL;
+ MMPort *port;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (!g_str_equal (subsystem, "net")) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot wait for port '%s/%s', unexpected link port subsystem", subsystem, name);
+ g_object_unref (task);
+ return;
+ }
+
+ key = g_strdup_printf ("%s%s", subsystem, name);
+ port = g_hash_table_lookup (self->priv->link_ports, key);
+ if (port) {
+ mm_obj_dbg (self, "no need to wait for port '%s/%s': already grabbed", subsystem, name);
+ g_task_return_pointer (task, g_object_ref (port), g_object_unref);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_slice_new0 (WaitLinkPortContext);
+ ctx->name = g_strdup (name);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)wait_link_port_context_free);
+
+ /* task ownership shared between timeout and signal handler */
+ ctx->timeout_id = g_timeout_add (timeout_ms,
+ (GSourceFunc) wait_link_port_timeout_cb,
+ task);
+ ctx->link_port_grabbed_id = g_signal_connect (self,
+ MM_BASE_MODEM_SIGNAL_LINK_PORT_GRABBED,
+ G_CALLBACK (wait_link_port_grabbed_cb),
+ task);
+
+ mm_obj_dbg (self, "waiting for port '%s/%s'...", subsystem, name);
+}
+
+/******************************************************************************/
+
+static void
+mm_base_modem_sync_ready (MMBaseModem *self,
+ GAsyncResult *res)
+{
+ g_autoptr (GError) error = NULL;
+
+ MM_BASE_MODEM_GET_CLASS (self)->sync_finish (self, res, &error);
+ if (error) {
+ mm_obj_warn (self, "synchronization failed");
+ }
+}
+
+void
+mm_base_modem_sync (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync != NULL);
+ g_assert (MM_BASE_MODEM_GET_CLASS (self)->sync_finish != NULL);
+
+ MM_BASE_MODEM_GET_CLASS (self)->sync (self,
+ (GAsyncReadyCallback) mm_base_modem_sync_ready,
+ NULL);
+}
+
gboolean
mm_base_modem_disable_finish (MMBaseModem *self,
GAsyncResult *res,
diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
index 24634814..75fd99f5 100644
--- a/src/mm-base-modem.h
+++ b/src/mm-base-modem.h
@@ -101,6 +101,22 @@ struct _MMBaseModemClass {
gboolean (*disable_finish) (MMBaseModem *self,
GAsyncResult *res,
GError **error);
+
+ /* Modem synchronization.
+ * When resuming in quick suspend/resume mode,
+ * this method triggers a synchronization of all modem interfaces */
+ void (* sync) (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* sync_finish) (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error);
+
+ /* signals */
+ void (* link_port_grabbed) (MMBaseModem *self,
+ MMPort *link_port);
+ void (* link_port_released) (MMBaseModem *self,
+ MMPort *link_port);
};
GType mm_base_modem_get_type (void);
@@ -199,6 +215,13 @@ gboolean mm_base_modem_disable_finish (MMBaseModem *self,
GAsyncResult *res,
GError **error);
+void mm_base_modem_sync (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_base_modem_sync_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error);
+
void mm_base_modem_process_sim_event (MMBaseModem *self);
#endif /* MM_BASE_MODEM_H */
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index a25883ac..6e47757e 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -11337,6 +11337,82 @@ enable (MMBaseModem *self,
g_object_unref (task);
}
+/*****************************************************************************/
+
+#if defined WITH_SYSTEMD_SUSPEND_RESUME
+
+typedef enum {
+ SYNCING_STEP_FIRST,
+ SYNCING_STEP_LAST,
+} SyncingStep;
+
+typedef struct {
+ SyncingStep step;
+} SyncingContext;
+
+static gboolean
+synchronize_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+syncing_step (GTask *task)
+{
+ MMBroadbandModem *self;
+ SyncingContext *ctx;
+
+ /* Don't run new steps if we're cancelled */
+ if (g_task_return_error_if_cancelled (task)) {
+ g_object_unref (task);
+ return;
+ }
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case SYNCING_STEP_FIRST:
+ ctx->step++;
+ /* fall through */
+
+ case SYNCING_STEP_LAST:
+ mm_obj_info (self, "resume synchronization state (%d/%d): all done",
+ ctx->step, SYNCING_STEP_LAST);
+ /* We are done without errors! */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+
+ default:
+ break;
+ }
+
+ g_assert_not_reached ();
+}
+
+/* 'sync' as function name conflicts with a declared function in unistd.h */
+static void
+synchronize (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SyncingContext *ctx;
+ GTask *task;
+
+ /* Create SyncingContext */
+ ctx = g_new0 (SyncingContext, 1);
+ ctx->step = SYNCING_STEP_FIRST;
+
+ /* Create sync steps task and execute it */
+ task = g_task_new (MM_BROADBAND_MODEM (self), NULL, callback, user_data);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)g_free);
+ syncing_step (task);
+}
+
+#endif
/*****************************************************************************/
@@ -12683,6 +12759,11 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
base_modem_class->disable = disable;
base_modem_class->disable_finish = disable_finish;
+#if defined WITH_SYSTEMD_SUSPEND_RESUME
+ base_modem_class->sync = synchronize;
+ base_modem_class->sync_finish = synchronize_finish;
+#endif
+
klass->setup_ports = setup_ports;
klass->initialization_started = initialization_started;
klass->initialization_started_finish = initialization_started_finish;
diff --git a/src/mm-context.c b/src/mm-context.c
index 6561127e..691ca82b 100644
--- a/src/mm-context.c
+++ b/src/mm-context.c
@@ -227,6 +227,7 @@ static gboolean test_no_udev;
#endif
#if defined WITH_SYSTEMD_SUSPEND_RESUME
static gboolean test_no_suspend_resume;
+static gboolean test_quick_suspend_resume;
#endif
static const GOptionEntry test_entries[] = {
@@ -258,6 +259,11 @@ static const GOptionEntry test_entries[] = {
"Disable suspend/resume support at runtime even if available",
NULL
},
+ {
+ "test-quick-suspend-resume", 0, 0, G_OPTION_ARG_NONE, &test_quick_suspend_resume,
+ "Enable quick suspend/resume support for modems which stay on during host suspension",
+ NULL
+ },
#endif
{ NULL }
};
@@ -308,6 +314,11 @@ mm_context_get_test_no_suspend_resume (void)
{
return test_no_suspend_resume;
}
+gboolean
+mm_context_get_test_quick_suspend_resume (void)
+{
+ return test_quick_suspend_resume;
+}
#endif
/*****************************************************************************/
diff --git a/src/mm-context.h b/src/mm-context.h
index 721fee88..276567fd 100644
--- a/src/mm-context.h
+++ b/src/mm-context.h
@@ -51,6 +51,7 @@ gboolean mm_context_get_test_no_udev (void);
#endif
#if defined WITH_SYSTEMD_SUSPEND_RESUME
gboolean mm_context_get_test_no_suspend_resume (void);
+gboolean mm_context_get_test_quick_suspend_resume (void);
#endif
#endif /* MM_CONTEXT_H */
--
2.31.1