summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2018-08-06 10:12:01 +0200
committerAleksander Morgado <aleksander@aleksander.es>2018-09-22 10:09:18 +0200
commit2e6bcd3171ee7c033fea54a74588c1e2ec1af1f6 (patch)
treee0b021282790da4df84883b28b6cce1177c00450
parentb15b01e26f883f4f52eae1d8eb3a7fbe405198d4 (diff)
downloadModemManager-2e6bcd3171ee7c033fea54a74588c1e2ec1af1f6.tar.gz
base-modem: allow parallel Enable() and Disable() requests
If additional Enable() requests are received while one is already ongoing, we queue them and will end up completing all with the same result once the first one finishes. Same logic also for Disable(). https://gitlab.freedesktop.org/mobile-broadband/ModemManager/issues/8 (cherry picked from commit c4766122476b53a89c606bd0c0cbbd0ec6d9826b)
-rw-r--r--src/mm-base-modem.c117
-rw-r--r--src/mm-broadband-modem.c6
2 files changed, 100 insertions, 23 deletions
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 12e96dc00..fa9303ca8 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -89,6 +89,10 @@ struct _MMBaseModemPrivate {
MMPortSerialAt *gps_control;
MMPortSerialGps *gps;
+ /* Support for parallel enable/disable operations */
+ GList *enable_tasks;
+ GList *disable_tasks;
+
#if defined WITH_QMI
/* QMI ports */
GList *qmi;
@@ -310,49 +314,123 @@ mm_base_modem_grab_port (MMBaseModem *self,
}
gboolean
-mm_base_modem_disable_finish (MMBaseModem *self,
- GAsyncResult *res,
- GError **error)
+mm_base_modem_disable_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
{
- return MM_BASE_MODEM_GET_CLASS (self)->disable_finish (self, res, error);
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+disable_ready (MMBaseModem *self,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+ GList *l;
+ GList *disable_tasks;
+
+ g_assert (self->priv->disable_tasks);
+ disable_tasks = self->priv->disable_tasks;
+ self->priv->disable_tasks = NULL;
+
+ MM_BASE_MODEM_GET_CLASS (self)->disable_finish (self, res, &error);
+ for (l = disable_tasks; l; l = g_list_next (l)) {
+ if (error)
+ g_task_return_error (G_TASK (l->data), g_error_copy (error));
+ else
+ g_task_return_boolean (G_TASK (l->data), TRUE);
+ }
+ g_clear_error (&error);
+
+ g_list_free_full (disable_tasks, (GDestroyNotify)g_object_unref);
}
void
-mm_base_modem_disable (MMBaseModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+mm_base_modem_disable (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ GTask *task;
+ gboolean run_disable;
+
g_assert (MM_BASE_MODEM_GET_CLASS (self)->disable != NULL);
g_assert (MM_BASE_MODEM_GET_CLASS (self)->disable_finish != NULL);
+ /* If the list of disable tasks is empty, we need to run */
+ run_disable = !self->priv->disable_tasks;
+
+ /* Store task */
+ task = g_task_new (self, self->priv->cancellable, callback, user_data);
+ self->priv->disable_tasks = g_list_append (self->priv->disable_tasks, task);
+
+ if (!run_disable)
+ return;
+
MM_BASE_MODEM_GET_CLASS (self)->disable (
self,
self->priv->cancellable,
- callback,
- user_data);
+ (GAsyncReadyCallback) disable_ready,
+ NULL);
}
gboolean
-mm_base_modem_enable_finish (MMBaseModem *self,
- GAsyncResult *res,
- GError **error)
+mm_base_modem_enable_finish (MMBaseModem *self,
+ GAsyncResult *res,
+ GError **error)
{
- return MM_BASE_MODEM_GET_CLASS (self)->enable_finish (self, res, error);
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+enable_ready (MMBaseModem *self,
+ GAsyncResult *res)
+{
+ GError *error = NULL;
+ GList *l;
+ GList *enable_tasks;
+
+ g_assert (self->priv->enable_tasks);
+ enable_tasks = self->priv->enable_tasks;
+ self->priv->enable_tasks = NULL;
+
+ MM_BASE_MODEM_GET_CLASS (self)->enable_finish (self, res, &error);
+ for (l = enable_tasks; l; l = g_list_next (l)) {
+ if (error)
+ g_task_return_error (G_TASK (l->data), g_error_copy (error));
+ else
+ g_task_return_boolean (G_TASK (l->data), TRUE);
+ }
+ g_clear_error (&error);
+
+ g_list_free_full (enable_tasks, (GDestroyNotify)g_object_unref);
}
void
-mm_base_modem_enable (MMBaseModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+mm_base_modem_enable (MMBaseModem *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ GTask *task;
+ gboolean run_enable;
+
g_assert (MM_BASE_MODEM_GET_CLASS (self)->enable != NULL);
g_assert (MM_BASE_MODEM_GET_CLASS (self)->enable_finish != NULL);
+ /* If the list of enable tasks is empty, we need to run */
+ run_enable = !self->priv->enable_tasks;
+
+ /* Store task */
+ task = g_task_new (self, self->priv->cancellable, callback, user_data);
+ self->priv->enable_tasks = g_list_append (self->priv->enable_tasks, task);
+
+ if (!run_enable)
+ return;
+
MM_BASE_MODEM_GET_CLASS (self)->enable (
self,
self->priv->cancellable,
- callback,
- user_data);
+ (GAsyncReadyCallback) enable_ready,
+ NULL);
}
gboolean
@@ -1417,6 +1495,9 @@ finalize (GObject *object)
* mm_auth_provider_cancel_for_owner (self->priv->authp, object);
*/
+ g_assert (!self->priv->enable_tasks);
+ g_assert (!self->priv->disable_tasks);
+
mm_dbg ("Modem (%s) '%s' completely disposed",
self->priv->plugin,
self->priv->device);
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 8afec66f9..8c0835661 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -10006,11 +10006,7 @@ enable (MMBaseModem *self,
break;
case MM_MODEM_STATE_ENABLING:
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_IN_PROGRESS,
- "Cannot enable modem: "
- "already being enabled");
+ g_assert_not_reached ();
break;
case MM_MODEM_STATE_ENABLED: