base-manager: add quick suspend/resume base

Quick suspend/resume infrastructure for
synchronizing the interfaces when resuming.
This commit is contained in:
Dylan Van Assche
2021-05-01 15:50:47 +02:00
committed by Aleksander Morgado
parent 940063419a
commit 38740e9d11
8 changed files with 200 additions and 1 deletions

View File

@@ -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
@@ -191,7 +198,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);

View File

@@ -52,6 +52,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);
@@ -723,6 +724,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 */

View File

@@ -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 */

View File

@@ -620,6 +620,31 @@ mm_base_modem_wait_link_port (MMBaseModem *self,
/******************************************************************************/
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,

View File

@@ -108,6 +108,16 @@ struct _MMBaseModemClass {
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);
@@ -231,6 +241,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 */

View File

@@ -11937,6 +11937,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
/*****************************************************************************/
@@ -13343,6 +13419,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;

View File

@@ -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
#if defined WITH_QRTR
static gboolean test_no_qrtr;
@@ -261,6 +262,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
#if defined WITH_QRTR
{
@@ -318,6 +324,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
#if defined WITH_QRTR

View File

@@ -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
#if defined WITH_QRTR
gboolean mm_context_get_test_no_qrtr (void);