base-manager: add quick suspend/resume base
Quick suspend/resume infrastructure for synchronizing the interfaces when resuming.
This commit is contained in:

committed by
Aleksander Morgado

parent
940063419a
commit
38740e9d11
14
src/main.c
14
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
|
||||
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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 */
|
||||
|
@@ -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,
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user