[PATCH 2/2] port-probe: simplify task completion

Aleksander Morgado aleksander at aleksander.es
Thu Mar 10 08:10:32 UTC 2016


We no longer need to complete in idle, because the limitation imposed by the
serial port methods no longer exists.
---
 src/mm-port-probe.c | 230 ++++++++++++++++++----------------------------------
 1 file changed, 81 insertions(+), 149 deletions(-)

diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index e260f34..c09b8a1 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -323,9 +323,6 @@ typedef struct {
     /* ---- MBIM probing specific context ---- */
     MMPortMbim *mbim_port;
 #endif
-
-    /* Error reporting during idle completion */
-    GError *possible_error;
 } PortProbeRunContext;
 
 static gboolean serial_probe_at       (MMPortProbe *self);
@@ -333,11 +330,8 @@ static gboolean serial_probe_qcdm     (MMPortProbe *self);
 static void     serial_probe_schedule (MMPortProbe *self);
 
 static void
-port_probe_run_context_cleanup (PortProbeRunContext *ctx)
+port_probe_run_context_free (PortProbeRunContext *ctx)
 {
-    /* We cleanup signal connections here, to be executed before a task is
-     * completed (and when it's freed) */
-
     if (ctx->cancellable && ctx->at_probing_cancellable_linked) {
         g_cancellable_disconnect (ctx->cancellable, ctx->at_probing_cancellable_linked);
         ctx->at_probing_cancellable_linked = 0;
@@ -352,13 +346,6 @@ port_probe_run_context_cleanup (PortProbeRunContext *ctx)
         g_signal_handler_disconnect (ctx->serial, ctx->buffer_full_id);
         ctx->buffer_full_id = 0;
     }
-}
-
-static void
-port_probe_run_context_free (PortProbeRunContext *ctx)
-{
-    /* Cleanup signals */
-    port_probe_run_context_cleanup (ctx);
 
     if (ctx->serial) {
         if (mm_port_serial_is_open (ctx->serial))
@@ -387,85 +374,9 @@ port_probe_run_context_free (PortProbeRunContext *ctx)
     if (ctx->cancellable)
         g_object_unref (ctx->cancellable);
 
-    /* We may have an error here if the task was completed
-     * with error and was cancelled at the same time */
-    if (ctx->possible_error)
-        g_error_free (ctx->possible_error);
-
     g_slice_free (PortProbeRunContext, ctx);
 }
 
-static gboolean
-task_return_in_idle_cb (GTask *task)
-{
-    PortProbeRunContext *ctx;
-
-    ctx = g_task_get_task_data (task);
-
-    if (g_task_return_error_if_cancelled (task))
-        goto out;
-
-    if (ctx->possible_error) {
-        g_task_return_error (task, ctx->possible_error);
-        ctx->possible_error = NULL;
-        goto out;
-    }
-
-    g_task_return_boolean (task, TRUE);
-
-out:
-    g_object_unref (task);
-    return G_SOURCE_REMOVE;
-}
-
-static void
-task_return_in_idle (MMPortProbe *self,
-                     GError      *error)
-{
-    PortProbeRunContext *ctx;
-    GTask               *task;
-
-    /* Steal task from private info */
-    g_assert (self->priv->task);
-    task = self->priv->task;
-    self->priv->task = NULL;
-
-    /* Early cleanup of signals */
-    ctx = g_task_get_task_data (task);
-    port_probe_run_context_cleanup (ctx);
-
-    /* We will propatate an error if we have one */
-    ctx->possible_error = error;
-
-    /* Schedule idle to complete.
-     *
-     * NOTE!!!!!!!
-     *
-     * Completing not-on-idle is very problematic due to how we process
-     * responses in the serial port: the response returned by the finish()
-     * call is constant, so that completion is always not-on-idle. And if we
-     * mix both tasks completed not-on-idle, we may end up reaching a point
-     * where the serial port is being closed while the serial port response
-     * is still being processed.
-     *
-     * By always completing this task on-idle, we make sure that the serial
-     * port gets closed always once the response processor has been finished.
-     */
-    g_idle_add ((GSourceFunc) task_return_in_idle_cb, task);
-}
-
-static gboolean
-task_return_error_in_idle_if_cancelled (MMPortProbe *self)
-{
-    if (!g_cancellable_is_cancelled (g_task_get_cancellable (self->priv->task)))
-        return FALSE;
-
-    /* We complete without error because the error is set afterwards by
-     * the GTask in g_task_return_error_if_cancelled() */
-    task_return_in_idle (self, NULL);
-    return TRUE;
-}
-
 /***************************************************************/
 /* QMI & MBIM */
 
@@ -616,8 +527,10 @@ wdm_probe (MMPortProbe *self)
     ctx->source_id = 0;
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
+    }
 
     /* QMI probing needed? */
     if ((ctx->flags & MM_PORT_PROBE_QMI) &&
@@ -634,7 +547,8 @@ wdm_probe (MMPortProbe *self)
     }
 
     /* All done now */
-    task_return_in_idle (self, NULL);
+    g_task_return_boolean (self->priv->task, TRUE);
+    g_clear_object (&self->priv->task);
     return G_SOURCE_REMOVE;
 }
 
@@ -657,8 +571,10 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
     ctx = g_task_get_task_data (self->priv->task);
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return;
+    }
 
     response = mm_port_serial_qcdm_command_finish (port, res, &error);
     if (!error) {
@@ -726,8 +642,10 @@ serial_probe_qcdm (MMPortProbe *self)
     ctx->source_id = 0;
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
+    }
 
     mm_dbg ("(%s/%s) probing QCDM...",
             g_udev_device_get_subsystem (self->priv->port),
@@ -747,25 +665,27 @@ serial_probe_qcdm (MMPortProbe *self)
     /* Open the QCDM port */
     ctx->serial = MM_PORT_SERIAL (mm_port_serial_qcdm_new (g_udev_device_get_name (self->priv->port)));
     if (!ctx->serial) {
-        task_return_in_idle (self,
-                             g_error_new (MM_CORE_ERROR,
-                                          MM_CORE_ERROR_FAILED,
-                                          "(%s/%s) Couldn't create QCDM port",
-                                          g_udev_device_get_subsystem (self->priv->port),
-                                          g_udev_device_get_name (self->priv->port)));
+        g_task_return_new_error (self->priv->task,
+                                 MM_CORE_ERROR,
+                                 MM_CORE_ERROR_FAILED,
+                                 "(%s/%s) Couldn't create QCDM port",
+                                 g_udev_device_get_subsystem (self->priv->port),
+                                 g_udev_device_get_name (self->priv->port));
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
     }
 
     /* Try to open the port */
     if (!mm_port_serial_open (ctx->serial, &error)) {
-        task_return_in_idle (self,
-                             g_error_new (MM_SERIAL_ERROR,
-                                          MM_SERIAL_ERROR_OPEN_FAILED,
-                                          "(%s/%s) Failed to open QCDM port: %s",
-                                          g_udev_device_get_subsystem (self->priv->port),
-                                          g_udev_device_get_name (self->priv->port),
-                                          (error ? error->message : "unknown error")));
+        g_task_return_new_error (self->priv->task,
+                                 MM_SERIAL_ERROR,
+                                 MM_SERIAL_ERROR_OPEN_FAILED,
+                                 "(%s/%s) Failed to open QCDM port: %s",
+                                 g_udev_device_get_subsystem (self->priv->port),
+                                 g_udev_device_get_name (self->priv->port),
+                                 (error ? error->message : "unknown error"));
         g_clear_error (&error);
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
     }
 
@@ -779,12 +699,13 @@ serial_probe_qcdm (MMPortProbe *self)
     len = qcdm_cmd_version_info_new ((char *) (verinfo->data + 1), 9);
     if (len <= 0) {
         g_byte_array_unref (verinfo);
-        task_return_in_idle (self,
-                             g_error_new (MM_SERIAL_ERROR,
-                                          MM_SERIAL_ERROR_OPEN_FAILED,
-                                          "(%s/%s) Failed to create QCDM versin info command",
-                                          g_udev_device_get_subsystem (self->priv->port),
-                                          g_udev_device_get_name (self->priv->port)));
+        g_task_return_new_error (self->priv->task,
+                                 MM_SERIAL_ERROR,
+                                 MM_SERIAL_ERROR_OPEN_FAILED,
+                                 "(%s/%s) Failed to create QCDM versin info command",
+                                 g_udev_device_get_subsystem (self->priv->port),
+                                 g_udev_device_get_name (self->priv->port));
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
     }
     verinfo->len = len + 1;
@@ -936,8 +857,10 @@ serial_probe_at_parse_response (MMPortSerialAt *port,
     ctx = g_task_get_task_data (self->priv->task);
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return;
+    }
 
     /* If AT probing cancelled, end this partial probing */
     if (g_cancellable_is_cancelled (ctx->at_probing_cancellable)) {
@@ -959,13 +882,14 @@ serial_probe_at_parse_response (MMPortSerialAt *port,
                                                &result_error)) {
         /* Were we told to abort the whole probing? */
         if (result_error) {
-            task_return_in_idle (self,
-                                 g_error_new (MM_CORE_ERROR,
-                                              MM_CORE_ERROR_UNSUPPORTED,
-                                              "(%s/%s) error while probing AT features: %s",
-                                              g_udev_device_get_subsystem (self->priv->port),
-                                              g_udev_device_get_name (self->priv->port),
-                                              result_error->message));
+            g_task_return_new_error (self->priv->task,
+                                     MM_CORE_ERROR,
+                                     MM_CORE_ERROR_UNSUPPORTED,
+                                     "(%s/%s) error while probing AT features: %s",
+                                     g_udev_device_get_subsystem (self->priv->port),
+                                     g_udev_device_get_name (self->priv->port),
+                                     result_error->message);
+            g_clear_object (&self->priv->task);
             goto out;
         }
 
@@ -1016,7 +940,7 @@ serial_probe_at (MMPortProbe *self)
     ctx->source_id = 0;
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self)) {
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
         g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
     }
@@ -1083,7 +1007,8 @@ at_custom_init_ready (MMPortProbe *self,
 
     if (!ctx->at_custom_init_finish (self, res, &error)) {
         /* All errors propagated up end up forcing an UNSUPPORTED result */
-        task_return_in_idle (self, error);
+        g_task_return_error (self->priv->task, error);
+        g_clear_object (&self->priv->task);
         return;
     }
 
@@ -1103,8 +1028,10 @@ serial_probe_schedule (MMPortProbe *self)
     ctx = g_task_get_task_data (self->priv->task);
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return;
+    }
 
     /* If we got some custom initialization setup requested, go on with it
      * first. */
@@ -1172,8 +1099,9 @@ serial_probe_schedule (MMPortProbe *self)
         return;
     }
 
-    /* All done! Finish asynchronously */
-    task_return_in_idle (self, NULL);
+    /* All done! */
+    g_task_return_boolean (self->priv->task, TRUE);
+    g_clear_object (&self->priv->task);
 }
 
 static void
@@ -1237,8 +1165,10 @@ serial_open_at (MMPortProbe *self)
     ctx->source_id = 0;
 
     /* If already cancelled, do nothing else */
-    if (task_return_error_in_idle_if_cancelled (self))
+    if (g_task_return_error_if_cancelled (self->priv->task)) {
+        g_clear_object (&self->priv->task);
         return G_SOURCE_REMOVE;
+    }
 
     /* Create AT serial port if not done before */
     if (!ctx->serial) {
@@ -1250,12 +1180,13 @@ serial_open_at (MMPortProbe *self)
 
         ctx->serial = MM_PORT_SERIAL (mm_port_serial_at_new (g_udev_device_get_name (self->priv->port), subsys));
         if (!ctx->serial) {
-            task_return_in_idle (self,
-                                 g_error_new (MM_CORE_ERROR,
-                                              MM_CORE_ERROR_FAILED,
-                                              "(%s/%s) couldn't create AT port",
-                                              g_udev_device_get_subsystem (self->priv->port),
-                                              g_udev_device_get_name (self->priv->port)));
+            g_task_return_new_error (self->priv->task,
+                                     MM_CORE_ERROR,
+                                     MM_CORE_ERROR_FAILED,
+                                     "(%s/%s) couldn't create AT port",
+                                     g_udev_device_get_subsystem (self->priv->port),
+                                     g_udev_device_get_name (self->priv->port));
+            g_clear_object (&self->priv->task);
             return G_SOURCE_REMOVE;
         }
 
@@ -1281,12 +1212,13 @@ serial_open_at (MMPortProbe *self)
         /* Abort if maximum number of open tries reached */
         if (++ctx->at_open_tries > 4) {
             /* took too long to open the port; give up */
-            task_return_in_idle (self,
-                                 g_error_new (MM_CORE_ERROR,
-                                              MM_CORE_ERROR_FAILED,
-                                              "(%s/%s) failed to open port after 4 tries",
-                                              g_udev_device_get_subsystem (self->priv->port),
-                                              g_udev_device_get_name (self->priv->port)));
+            g_task_return_new_error (self->priv->task,
+                                     MM_CORE_ERROR,
+                                     MM_CORE_ERROR_FAILED,
+                                     "(%s/%s) failed to open port after 4 tries",
+                                     g_udev_device_get_subsystem (self->priv->port),
+                                     g_udev_device_get_name (self->priv->port));
+            g_clear_object (&self->priv->task);
             g_clear_error (&error);
             return G_SOURCE_REMOVE;
         }
@@ -1298,14 +1230,14 @@ serial_open_at (MMPortProbe *self)
             return G_SOURCE_REMOVE;
         }
 
-        port_probe_run_context_cleanup (ctx);
-        task_return_in_idle (self,
-                             g_error_new (MM_SERIAL_ERROR,
-                                          MM_SERIAL_ERROR_OPEN_FAILED,
-                                          "(%s/%s) failed to open port: %s",
-                                          g_udev_device_get_subsystem (self->priv->port),
-                                          g_udev_device_get_name (self->priv->port),
-                                          (error ? error->message : "unknown error")));
+        g_task_return_new_error (self->priv->task,
+                                 MM_SERIAL_ERROR,
+                                 MM_SERIAL_ERROR_OPEN_FAILED,
+                                 "(%s/%s) failed to open port: %s",
+                                 g_udev_device_get_subsystem (self->priv->port),
+                                 g_udev_device_get_name (self->priv->port),
+                                 (error ? error->message : "unknown error"));
+        g_clear_object (&self->priv->task);
         g_clear_error (&error);
         return G_SOURCE_REMOVE;
     }
@@ -1411,8 +1343,8 @@ mm_port_probe_run (MMPortProbe                *self,
         mm_dbg ("(%s/%s) port probing finished: no more probings needed",
                 g_udev_device_get_subsystem (self->priv->port),
                 g_udev_device_get_name (self->priv->port));
-        port_probe_run_context_cleanup (ctx);
-        task_return_in_idle (self, NULL);
+        g_task_return_boolean (self->priv->task, TRUE);
+        g_clear_object (&self->priv->task);
         return;
     }
 
-- 
2.7.1



More information about the ModemManager-devel mailing list