diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2024-09-13 11:17:48 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksandermj@chromium.org> | 2024-09-30 07:55:05 +0000 |
commit | be668462c07cbf3af549a9b225004e4e8d8cc596 (patch) | |
tree | 51a4a1c4c97b3b6ab7306c78b9df4f43b63dca9b /src/mm-base-modem.c | |
parent | 8e0cbd9c94ffd7f9122ade0f4cea198c7c4dfd0a (diff) |
base-modem: synchronize initialize/enable/disable/sync operations
Each of these now holds an exclusive lock, so all these operations are
synchronized.
This logic can be tested by queing different enable/disable operations
one after the other, e.g.:
mmcli -m a -d & --> Disable 1
sleep 0.2
mmcli -m a -e & --> Enable 1
sleep 0.2
mmcli -m a -e & --> Enable 2
sleep 0.2
mmcli -m a -d & --> Disable 2
sleep 0.2
mmcli -m a -e & --> Enable 3
sleep 0.2
mmcli -m a -d & --> Disable 3
This previous sequence produces MM logs as follows:
<dbg> [1726566352.936025] [modem0] [operation 9] default - disable: scheduled --> Disable 1 requested
<dbg> [1726566352.936399] [modem0] [operation 9] default - disable: lock acquired --> Disable 1 started
<dbg> [1726566353.136445] [modem0] [operation 10] default - enable: scheduled --> Enable 1 requested
<dbg> [1726566353.202980] [modem0] [operation 9] default - disable: lock released --> Disable 1 finished
<dbg> [1726566353.203526] [modem0] [operation 10] default - enable: lock acquired --> Enable 1 started
<dbg> [1726566353.320057] [modem0] [operation 11] default - enable: scheduled --> Enable 2 requested
<dbg> [1726566353.440931] [modem0] [operation 10] default - enable: lock released --> Enable 1 finished
<dbg> [1726566353.443238] [modem0] [operation 11] default - enable: lock acquired --> Enable 2 started
<dbg> [1726566353.452984] [modem0] [operation 11] default - enable: lock released --> Enable 2 finished
<dbg> [1726566353.517512] [modem0] [operation 12] default - disable: scheduled --> Disable 2 requested
<dbg> [1726566353.517699] [modem0] [operation 12] default - disable: lock acquired --> Disable 2 started
<dbg> [1726566353.688695] [modem0] [operation 12] default - disable: lock released --> Disable 2 finished
<dbg> [1726566353.718237] [modem0] [operation 13] default - enable: scheduled --> Enable 3 requested
<dbg> [1726566353.718417] [modem0] [operation 13] default - enable: lock acquired --> Enable 3 started
<dbg> [1726566353.937122] [modem0] [operation 14] default - disable: scheduled --> Disable 3 requested
<dbg> [1726566353.970791] [modem0] [operation 13] default - enable: lock released --> Enable 3 finished
<dbg> [1726566353.970964] [modem0] [operation 14] default - disable: lock acquired --> Disable 3 started
<dbg> [1726566354.170938] [modem0] [operation 14] default - disable: lock released --> Disable 3 finished
Diffstat (limited to 'src/mm-base-modem.c')
-rw-r--r-- | src/mm-base-modem.c | 249 |
1 files changed, 195 insertions, 54 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c index 0e0fe00c..bef3ddf0 100644 --- a/src/mm-base-modem.c +++ b/src/mm-base-modem.c @@ -712,51 +712,189 @@ mm_base_modem_wait_link_port (MMBaseModem *self, } /******************************************************************************/ +/* Common support to perform state update/sync operations with the base modem. */ +typedef enum { + STATE_OPERATION_TYPE_INITIALIZE, + STATE_OPERATION_TYPE_ENABLE, + STATE_OPERATION_TYPE_DISABLE, #if defined WITH_SUSPEND_RESUME + STATE_OPERATION_TYPE_SYNC, +#endif +} StateOperationType; -gboolean -mm_base_modem_sync_finish (MMBaseModem *self, - GAsyncResult *res, - GError **error) +typedef struct { + StateOperation operation; + StateOperationFinish operation_finish; + gssize operation_id; +} StateOperationContext; + +static void +state_operation_context_free (StateOperationContext *ctx) +{ + g_assert (ctx->operation_id < 0); + g_slice_free (StateOperationContext, ctx); +} + +static gboolean +state_operation_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error) { return g_task_propagate_boolean (G_TASK (res), error); } static void -sync_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) +state_operation_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) { GError *error = NULL; - if (!MM_BASE_MODEM_GET_CLASS (self)->sync_finish (self, res, &error)) + StateOperationContext *ctx; + + ctx = g_task_get_task_data (task); + + if (ctx->operation_id >= 0) { + mm_base_modem_operation_unlock (self, ctx->operation_id); + ctx->operation_id = (gssize) -1; + } + + if (!ctx->operation_finish (self, res, &error)) g_task_return_error (task, error); else g_task_return_boolean (task, TRUE); g_object_unref (task); } -void -mm_base_modem_sync (MMBaseModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +static void +state_operation_run (GTask *task) { - GTask *task; + MMBaseModem *self; + StateOperationContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + ctx->operation (self, + self->priv->cancellable, + (GAsyncReadyCallback) state_operation_ready, + task); +} + +static void +lock_before_state_operation_ready (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + StateOperationContext *ctx; + + ctx = g_task_get_task_data (task); + + ctx->operation_id = mm_base_modem_operation_lock_finish (self, res, &error); + if (ctx->operation_id < 0) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + state_operation_run (task); +} + +static void +state_operation (MMBaseModem *self, + StateOperationType operation_type, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + StateOperationContext *ctx; + gboolean optional; + const gchar *operation_description; + + ctx = g_slice_new0 (StateOperationContext); + ctx->operation_id = (gssize) -1; + + /* configure operation to run */ + switch (operation_type) { + case STATE_OPERATION_TYPE_INITIALIZE: + operation_description = "initialization"; + optional = FALSE; + ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->initialize; + ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->initialize_finish; + break; + case STATE_OPERATION_TYPE_ENABLE: + operation_description = "enabling"; + optional = FALSE; + ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->enable; + ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->enable_finish; + break; + case STATE_OPERATION_TYPE_DISABLE: + operation_description = "disabling"; + optional = FALSE; + ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->disable; + ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->disable_finish; + break; +#if defined WITH_SUSPEND_RESUME + case STATE_OPERATION_TYPE_SYNC: + operation_description = "sync"; + optional = TRUE; + ctx->operation = MM_BASE_MODEM_GET_CLASS (self)->sync; + ctx->operation_finish = MM_BASE_MODEM_GET_CLASS (self)->sync_finish; + break; +#endif + default: + g_assert_not_reached (); + } task = g_task_new (self, NULL, callback, user_data); + g_task_set_task_data (task, ctx, (GDestroyNotify) state_operation_context_free); - if (!MM_BASE_MODEM_GET_CLASS (self)->sync || - !MM_BASE_MODEM_GET_CLASS (self)->sync_finish) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Suspend/resume quick synchronization unsupported"); + if (optional && (!ctx->operation || !ctx->operation_finish)) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "Unsupported"); g_object_unref (task); return; } + g_assert (ctx->operation && ctx->operation_finish); - MM_BASE_MODEM_GET_CLASS (self)->sync (self, - (GAsyncReadyCallback) sync_ready, - task); + if (operation_lock == MM_BASE_MODEM_OPERATION_LOCK_ALREADY_ACQUIRED) { + state_operation_run (task); + return; + } + + g_assert (operation_lock == MM_BASE_MODEM_OPERATION_LOCK_REQUIRED); + mm_base_modem_operation_lock (self, + MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT, + operation_description, + (GAsyncReadyCallback) lock_before_state_operation_ready, + task); +} + +/******************************************************************************/ + +#if defined WITH_SUSPEND_RESUME + +gboolean +mm_base_modem_sync_finish (MMBaseModem *self, + GAsyncResult *res, + GError **error) +{ + return state_operation_finish (self, res, error); +} + +void +mm_base_modem_sync (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) +{ + state_operation (self, + STATE_OPERATION_TYPE_SYNC, + operation_lock, + callback, + user_data); } #endif /* WITH_SUSPEND_RESUME */ @@ -768,67 +906,70 @@ mm_base_modem_disable_finish (MMBaseModem *self, GAsyncResult *res, GError **error) { - return MM_BASE_MODEM_GET_CLASS (self)->disable_finish (self, res, error); + return state_operation_finish (self, res, error); } void -mm_base_modem_disable (MMBaseModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +mm_base_modem_disable (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) { - g_assert (MM_BASE_MODEM_GET_CLASS (self)->disable != NULL); - g_assert (MM_BASE_MODEM_GET_CLASS (self)->disable_finish != NULL); - MM_BASE_MODEM_GET_CLASS (self)->disable ( - self, - self->priv->cancellable, - callback, - user_data); + state_operation (self, + STATE_OPERATION_TYPE_DISABLE, + operation_lock, + callback, + user_data); } +/******************************************************************************/ + gboolean mm_base_modem_enable_finish (MMBaseModem *self, GAsyncResult *res, GError **error) { - return MM_BASE_MODEM_GET_CLASS (self)->enable_finish (self, res, error); + return state_operation_finish (self, res, error); } void -mm_base_modem_enable (MMBaseModem *self, - GAsyncReadyCallback callback, - gpointer user_data) +mm_base_modem_enable (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) { - g_assert (MM_BASE_MODEM_GET_CLASS (self)->enable != NULL); - g_assert (MM_BASE_MODEM_GET_CLASS (self)->enable_finish != NULL); - MM_BASE_MODEM_GET_CLASS (self)->enable ( - self, - self->priv->cancellable, - callback, - user_data); + state_operation (self, + STATE_OPERATION_TYPE_ENABLE, + operation_lock, + callback, + user_data); } +/******************************************************************************/ + gboolean mm_base_modem_initialize_finish (MMBaseModem *self, GAsyncResult *res, GError **error) { - return MM_BASE_MODEM_GET_CLASS (self)->initialize_finish (self, res, error); + return state_operation_finish (self, res, error); } void -mm_base_modem_initialize (MMBaseModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_assert (MM_BASE_MODEM_GET_CLASS (self)->initialize != NULL); - g_assert (MM_BASE_MODEM_GET_CLASS (self)->initialize_finish != NULL); - MM_BASE_MODEM_GET_CLASS (self)->initialize ( - self, - self->priv->cancellable, - callback, - user_data); +mm_base_modem_initialize (MMBaseModem *self, + MMBaseModemOperationLock operation_lock, + GAsyncReadyCallback callback, + gpointer user_data) +{ + state_operation (self, + STATE_OPERATION_TYPE_INITIALIZE, + operation_lock, + callback, + user_data); } +/******************************************************************************/ + void mm_base_modem_set_hotplugged (MMBaseModem *self, gboolean hotplugged) |