aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2024-09-13 12:26:26 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2024-09-30 11:07:05 +0000
commit0aef4c422f5f686741f8943f479ff8d43b751f3d (patch)
treeb0273eb42b1f46a1acd295cdc2d5f278b6b88422
parent3510ffc41872d98c336f0cdf73bc5bbdef4dc084 (diff)
base-modem: new 'override' operation lock type
If a request to lock the operation with the override type arrives, all pending operations will be immediately cancelled, and no new lock requests will be allowed.
-rw-r--r--src/mm-base-modem.c92
-rw-r--r--src/mm-base-modem.h4
2 files changed, 88 insertions, 8 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index bef3ddf0..6348af33 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -136,8 +136,13 @@ struct _MMBaseModemPrivate {
* organized ports */
GHashTable *link_ports;
- /* Scheduled operations */
- GList *scheduled_operations;
+ /* Scheduled operations. The forbidden_forever flag will be set to TRUE
+ * if an "override" operation is requested, and will never be set to FALSE
+ * back, it is expected the modem object will eventually be removed after
+ * the operation has finished,
+ */
+ GList *scheduled_operations;
+ gboolean scheduled_operations_forbidden_forever;
};
guint
@@ -1831,6 +1836,55 @@ base_modem_operation_run (MMBaseModem *self)
g_object_unref (task);
}
+static gboolean
+abort_pending_operation_in_idle_cb (GTask *task)
+{
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
+ "Operation aborted");
+ g_object_unref (task);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+abort_pending_operations (MMBaseModem *self)
+{
+ GList *head = NULL;
+ GList *abort_operations;
+
+ /* Steal the whole list before iterating it */
+ abort_operations = g_steal_pointer (&self->priv->scheduled_operations);
+
+ while (abort_operations) {
+ OperationInfo *info;
+ GTask *task;
+
+ info = (OperationInfo *)(abort_operations->data);
+
+ /* Head operation may already be running, we should not abort that one */
+ if (!info->wait_task) {
+ /* Keep the head item as a single-element list */
+ g_assert (!head);
+ head = abort_operations;
+ abort_operations = g_list_remove_link (abort_operations, head);
+ continue;
+ }
+
+ g_assert (info->wait_task);
+ mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: aborted early",
+ info->id,
+ mm_base_modem_operation_priority_get_string (info->priority),
+ info->description);
+
+ task = g_steal_pointer (&info->wait_task);
+ g_idle_add ((GSourceFunc) abort_pending_operation_in_idle_cb, task);
+ abort_operations = g_list_delete_link (abort_operations, abort_operations);
+ operation_info_free (info);
+ }
+
+ /* Keep the running head, if any, in the list of scheduled operations */
+ self->priv->scheduled_operations = head;
+}
+
void
mm_base_modem_operation_lock (MMBaseModem *self,
MMBaseModemOperationPriority priority,
@@ -1838,14 +1892,24 @@ mm_base_modem_operation_lock (MMBaseModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ GTask *task;
OperationInfo *info;
static gssize operation_id = 0;
+ task = g_task_new (self, NULL, callback, user_data);
+ if (self->priv->scheduled_operations_forbidden_forever) {
+ mm_obj_dbg (self, "operation forbidden as override has already been requested");
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
+ "Operation aborted");
+ g_object_unref (task);
+ return;
+ }
+
info = g_slice_new0 (OperationInfo);
info->id = operation_id;
info->priority = priority;
info->description = g_strdup (description);
- info->wait_task = g_task_new (self, NULL, callback, user_data);
+ info->wait_task = task;
if (operation_id == G_MAXSSIZE) {
mm_obj_dbg (self, "operation id reset");
@@ -1853,11 +1917,23 @@ mm_base_modem_operation_lock (MMBaseModem *self,
} else
operation_id++;
- mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: scheduled",
- info->id,
- mm_base_modem_operation_priority_get_string (info->priority),
- info->description);
- self->priv->scheduled_operations = g_list_append (self->priv->scheduled_operations, info);
+ if (info->priority == MM_BASE_MODEM_OPERATION_PRIORITY_OVERRIDE) {
+ mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: override requested - no new operations will be allowed",
+ info->id,
+ mm_base_modem_operation_priority_get_string (info->priority),
+ info->description);
+ g_assert (!self->priv->scheduled_operations_forbidden_forever);
+ self->priv->scheduled_operations_forbidden_forever = TRUE;
+ abort_pending_operations (self);
+ self->priv->scheduled_operations = g_list_append (self->priv->scheduled_operations, info);
+ } else if (info->priority == MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT) {
+ mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: scheduled",
+ info->id,
+ mm_base_modem_operation_priority_get_string (info->priority),
+ info->description);
+ self->priv->scheduled_operations = g_list_append (self->priv->scheduled_operations, info);
+ } else
+ g_assert_not_reached ();
base_modem_operation_run (self);
}
diff --git a/src/mm-base-modem.h b/src/mm-base-modem.h
index c7a5a4e9..a02bdf4c 100644
--- a/src/mm-base-modem.h
+++ b/src/mm-base-modem.h
@@ -233,6 +233,10 @@ typedef enum { /*< underscore_name=mm_base_modem_operation_priority >*/
/* Default operations are scheduled at the end of the list of pending
* operations */
MM_BASE_MODEM_OPERATION_PRIORITY_DEFAULT,
+ /* An override operation will make all pending operations be cancelled, and
+ * it will also disallow adding new operations. This type of operation would
+ * be the last one expected in a modem object. */
+ MM_BASE_MODEM_OPERATION_PRIORITY_OVERRIDE,
} MMBaseModemOperationPriority;
void mm_base_modem_operation_lock (MMBaseModem *self,