aboutsummaryrefslogtreecommitdiff
path: root/src/mm-base-modem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-base-modem.c')
-rw-r--r--src/mm-base-modem.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index d8fd4164..f1979689 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -36,6 +36,7 @@
#include "mm-log-object.h"
#include "mm-port-enums-types.h"
+#include "mm-daemon-enums-types.h"
#include "mm-serial-parsers.h"
#include "mm-modem-helpers.h"
@@ -138,6 +139,9 @@ struct _MMBaseModemPrivate {
/* Additional port links grabbed after having
* organized ports */
GHashTable *link_ports;
+
+ /* Scheduled operations */
+ GList *scheduled_operations;
};
guint
@@ -1716,6 +1720,206 @@ mm_base_modem_authorize (MMBaseModem *self,
}
/*****************************************************************************/
+/* Exclusive operation */
+
+typedef struct {
+ gssize id;
+ MMBaseModemOperationPriority priority;
+ gchar *description;
+ GTask *wait_task;
+} OperationInfo;
+
+static void
+operation_info_free (OperationInfo *info)
+{
+ g_assert (!info->wait_task);
+ g_free (info->description);
+ g_slice_free (OperationInfo, info);
+}
+
+/* Exclusive operation lock */
+
+gssize
+mm_base_modem_operation_lock_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_int (G_TASK (res), error);
+}
+
+static void
+base_modem_operation_run (MMBaseModem *self)
+{
+ OperationInfo *info;
+ GTask *task;
+
+ if (!self->priv->scheduled_operations)
+ return;
+
+ /* Do nothing if head operation is already running */
+ info = (OperationInfo *)(self->priv->scheduled_operations->data);
+ if (!info->wait_task)
+ return;
+
+ /* Run the operation in head of the list */
+ mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: lock acquired",
+ info->id,
+ mm_base_modem_operation_priority_get_string (info->priority),
+ info->description);
+ task = g_steal_pointer (&info->wait_task);
+ g_task_return_int (task, info->id);
+ g_object_unref (task);
+}
+
+void
+mm_base_modem_operation_lock (MMBaseModem *self,
+ MMBaseModemOperationPriority priority,
+ const gchar *description,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ OperationInfo *info;
+ static gssize operation_id = 0;
+
+ 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);
+
+ if (operation_id == G_MAXSSIZE) {
+ mm_obj_dbg (self, "operation id reset");
+ operation_id = 0;
+ } 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);
+
+ base_modem_operation_run (self);
+}
+
+/* Exclusive operation unlock */
+
+void
+mm_base_modem_operation_unlock (MMBaseModem *self,
+ gssize operation_id)
+{
+ OperationInfo *info;
+
+ g_assert (self->priv->scheduled_operations);
+
+ info = (OperationInfo *)(self->priv->scheduled_operations->data);
+ g_assert (!info->wait_task);
+ g_assert (info->id == operation_id);
+
+ mm_obj_dbg (self, "[operation %" G_GSSIZE_FORMAT "] %s - %s: lock released",
+ info->id,
+ mm_base_modem_operation_priority_get_string (info->priority),
+ info->description);
+
+ /* Remove head list item and free its contents */
+ self->priv->scheduled_operations = g_list_delete_link (self->priv->scheduled_operations,
+ self->priv->scheduled_operations);
+ operation_info_free (info);
+
+ /* Run next, if any */
+ base_modem_operation_run (self);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ GDBusMethodInvocation *invocation;
+ MMBaseModemOperationPriority operation_priority;
+ gchar *operation_description;
+} AuthorizeAndOperationLockContext;
+
+static void
+authorize_and_operation_lock_context_free (AuthorizeAndOperationLockContext *ctx)
+{
+ g_object_unref (ctx->invocation);
+ g_free (ctx->operation_description);
+ g_slice_free (AuthorizeAndOperationLockContext, ctx);
+}
+
+gssize
+mm_base_modem_authorize_and_operation_lock_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_int (G_TASK (res), error);
+}
+
+static void
+lock_after_authorize_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ gssize operation_id;
+
+ operation_id = mm_base_modem_operation_lock_finish (self, res, &error);
+ if (operation_id < 0)
+ g_task_return_error (task, error);
+ else
+ g_task_return_int (task, operation_id);
+ g_object_unref (task);
+}
+
+static void
+authorize_before_lock_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ AuthorizeAndOperationLockContext *ctx;
+
+ if (!mm_base_modem_authorize_finish (self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx = g_task_get_task_data (task);
+ mm_base_modem_operation_lock (self,
+ ctx->operation_priority,
+ ctx->operation_description,
+ (GAsyncReadyCallback) lock_after_authorize_ready,
+ task);
+}
+
+void
+mm_base_modem_authorize_and_operation_lock (MMBaseModem *self,
+ GDBusMethodInvocation *invocation,
+ const gchar *authorization,
+ MMBaseModemOperationPriority operation_priority,
+ const gchar *operation_description,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ AuthorizeAndOperationLockContext *ctx;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_slice_new0 (AuthorizeAndOperationLockContext);
+ ctx->invocation = g_object_ref (invocation);
+ ctx->operation_priority = operation_priority;
+ ctx->operation_description = g_strdup (operation_description);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)authorize_and_operation_lock_context_free);
+
+ mm_base_modem_authorize (self,
+ invocation,
+ authorization,
+ (GAsyncReadyCallback)authorize_before_lock_ready,
+ task);
+}
+
+/*****************************************************************************/
const gchar *
mm_base_modem_get_device (MMBaseModem *self)
@@ -2020,6 +2224,7 @@ finalize (GObject *object)
g_assert (!self->priv->enable_tasks);
g_assert (!self->priv->disable_tasks);
+ g_assert (!self->priv->scheduled_operations);
mm_obj_dbg (self, "completely disposed");