<div dir="ltr">LGTM, for syntax & control flow. Like the idea but I'm biased on this one ;)</div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, May 21, 2017 at 1:49 PM, Aleksander Morgado <span dir="ltr"><<a href="mailto:aleksander@aleksander.es" target="_blank">aleksander@aleksander.es</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Plugins have two ways to update signal quality and access technology<br>
values: via unsolicited messages or via polling periodically.<br>
<br>
Instead of keeping separate contexts for polling signal quality and<br>
access technology values, we setup a common timeout to trigger<br>
both. This allows us to simplify in which case the explicit update is<br>
required, whenever one is needed to be explicitly updated, the other<br>
one should also be.<br>
<br>
The logic now also allows plugins to return an UNSUPPORTED error in<br>
either load_signal_quality() and/or load_access_technologies() to tell<br>
the interface logic that the polling of the specific item shouldn't be<br>
performed (e.g. if the updates are expected via unsolicited messages).<br>
<br>
If both signal quality and access technology polling is flagged as<br>
disabled, we totally disable the polling logic internally.<br>
<br>
The new SignalCheckContext is bound to the lifetime of the object so<br>
that we can keep the value of the supported flags until the object is<br>
destroyed.<br>
---<br>
 plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c |   8 +-<br>
 src/mm-iface-modem-3gpp.c                        |   7 +-<br>
 src/mm-iface-modem.c                             | 587 ++++++++++++-----------<br>
 src/mm-iface-modem.h                             |   6 +-<br>
 4 files changed, 310 insertions(+), 298 deletions(-)<br>
<br>
diff --git a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
index 1509debf..3037ee9a 100644<br>
--- a/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
+++ b/plugins/cinterion/mm-<wbr>broadband-modem-cinterion.c<br>
@@ -850,8 +850,8 @@ allowed_access_technology_<wbr>update_ready (MMBroadbandModemCinterion *self,<br>
         /* Let the error be critical. */<br>
         g_simple_async_result_take_<wbr>error (operation_result, error);<br>
     else {<br>
-        /* Request immediate access tech update */<br>
-        mm_iface_modem_refresh_access_<wbr>technologies (MM_IFACE_MODEM (self));<br>
+        /* Request immediate signal update */<br>
+        mm_iface_modem_refresh_signal (MM_IFACE_MODEM (self));<br>
         g_simple_async_result_set_op_<wbr>res_gboolean (operation_result, TRUE);<br>
     }<br>
     g_simple_async_result_complete (operation_result);<br>
@@ -1148,8 +1148,8 @@ scfg_set_ready (MMBaseModem *self,<br>
         /* Let the error be critical */<br>
         g_simple_async_result_take_<wbr>error (operation_result, error);<br>
     else {<br>
-        /* Request immediate access tech update */<br>
-        mm_iface_modem_refresh_access_<wbr>technologies (MM_IFACE_MODEM (self));<br>
+        /* Request immediate signal update */<br>
+        mm_iface_modem_refresh_signal (MM_IFACE_MODEM (self));<br>
         g_simple_async_result_set_op_<wbr>res_gboolean (operation_result, TRUE);<br>
     }<br>
<br>
diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c<br>
index 8b93550a..bcd12e85 100644<br>
--- a/src/mm-iface-modem-3gpp.c<br>
+++ b/src/mm-iface-modem-3gpp.c<br>
@@ -307,8 +307,11 @@ run_registration_checks_ready (MMIfaceModem3gpp *self,<br>
         current_registration_state == MM_MODEM_3GPP_REGISTRATION_<wbr>STATE_ROAMING_SMS_ONLY ||<br>
         current_registration_state == MM_MODEM_3GPP_REGISTRATION_<wbr>STATE_HOME_CSFB_NOT_PREFERRED ||<br>
         current_registration_state == MM_MODEM_3GPP_REGISTRATION_<wbr>STATE_ROAMING_CSFB_NOT_<wbr>PREFERRED) {<br>
-        /* Request immediate access tech update */<br>
-        mm_iface_modem_refresh_access_<wbr>technologies (MM_IFACE_MODEM (ctx->self));<br>
+        /* Request immediate access tech and signal update: we may have changed<br>
+         * from home to roaming or viceversa, both registered states, so there<br>
+         * wouldn't be an explicit refresh triggered from the modem interface as<br>
+         * the modem never got un-registered during the sequence. */<br>
+        mm_iface_modem_refresh_signal (MM_IFACE_MODEM (ctx->self));<br>
         mm_dbg ("Modem is currently registered in a 3GPP network");<br>
         g_simple_async_result_set_op_<wbr>res_gboolean (ctx->result, TRUE);<br>
         register_in_network_context_<wbr>complete_and_free (ctx);<br>
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c<br>
index ecb351a0..bbf0fdc4 100644<br>
--- a/src/mm-iface-modem.c<br>
+++ b/src/mm-iface-modem.c<br>
@@ -29,21 +29,20 @@<br>
 #include "mm-log.h"<br>
 #include "mm-context.h"<br>
<br>
-#define SIGNAL_QUALITY_RECENT_TIMEOUT_<wbr>SEC        60<br>
-#define SIGNAL_QUALITY_INITIAL_CHECK_<wbr>TIMEOUT_SEC 3<br>
-#define SIGNAL_QUALITY_CHECK_TIMEOUT_<wbr>SEC         30<br>
-#define ACCESS_TECHNOLOGIES_CHECK_<wbr>TIMEOUT_SEC    30<br>
+#define SIGNAL_QUALITY_RECENT_TIMEOUT_<wbr>SEC 60<br>
<br>
-#define STATE_UPDATE_CONTEXT_TAG              "state-update-context-tag"<br>
-#define SIGNAL_QUALITY_UPDATE_CONTEXT_<wbr>TAG     "signal-quality-update-<wbr>context-tag"<br>
-#define SIGNAL_QUALITY_CHECK_CONTEXT_<wbr>TAG      "signal-quality-check-context-<wbr>tag"<br>
-#define ACCESS_TECHNOLOGIES_CHECK_<wbr>CONTEXT_TAG "access-technologies-check-<wbr>context-tag"<br>
-#define RESTART_INITIALIZE_IDLE_TAG           "restart-initialize-tag"<br>
+#define SIGNAL_CHECK_INITIAL_RETRIES      5<br>
+#define SIGNAL_CHECK_INITIAL_TIMEOUT_<wbr>SEC  3<br>
+#define SIGNAL_CHECK_TIMEOUT_SEC          30<br>
+<br>
+#define STATE_UPDATE_CONTEXT_TAG          "state-update-context-tag"<br>
+#define SIGNAL_QUALITY_UPDATE_CONTEXT_<wbr>TAG "signal-quality-update-<wbr>context-tag"<br>
+#define SIGNAL_CHECK_CONTEXT_TAG          "signal-check-context-tag"<br>
+#define RESTART_INITIALIZE_IDLE_TAG       "restart-initialize-tag"<br>
<br>
 static GQuark state_update_context_quark;<br>
 static GQuark signal_quality_update_context_<wbr>quark;<br>
-static GQuark signal_quality_check_context_<wbr>quark;<br>
-static GQuark access_technologies_check_<wbr>context_quark;<br>
+static GQuark signal_check_context_quark;<br>
 static GQuark restart_initialize_idle_quark;<br>
<br>
 /*****************************<wbr>******************************<wbr>******************/<br>
@@ -943,152 +942,6 @@ mm_iface_modem_update_access_<wbr>technologies (MMIfaceModem *self,<br>
 /*****************************<wbr>******************************<wbr>******************/<br>
<br>
 typedef struct {<br>
-    guint timeout_source;<br>
-    gboolean running;<br>
-} AccessTechnologiesCheckContext<wbr>;<br>
-<br>
-static void<br>
-access_technologies_check_<wbr>context_free (<wbr>AccessTechnologiesCheckContext *ctx)<br>
-{<br>
-    if (ctx->timeout_source)<br>
-        g_source_remove (ctx->timeout_source);<br>
-    g_free (ctx);<br>
-}<br>
-<br>
-static void<br>
-access_technologies_check_<wbr>ready (MMIfaceModem *self,<br>
-                                 GAsyncResult *res)<br>
-{<br>
-    GError *error = NULL;<br>
-    MMModemAccessTechnology access_technologies = MM_MODEM_ACCESS_TECHNOLOGY_<wbr>UNKNOWN;<br>
-    guint mask = MM_MODEM_ACCESS_TECHNOLOGY_<wbr>ANY;<br>
-    AccessTechnologiesCheckContext *ctx;<br>
-<br>
-    if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies_finish (<br>
-            self,<br>
-            res,<br>
-            &access_technologies,<br>
-            &mask,<br>
-            &error)) {<br>
-        /* Ignore issues when the operation is unsupported, don't even log */<br>
-        if (!g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED))<br>
-            mm_dbg ("Couldn't refresh access technologies: '%s'", error->message);<br>
-        g_error_free (error);<br>
-    } else<br>
-        mm_iface_modem_update_access_<wbr>technologies (self, access_technologies, mask);<br>
-<br>
-    /* Remove the running tag. Note that the context may have been removed by<br>
-     * mm_iface_modem_shutdown when this function is invoked as a callback of<br>
-     * load_access_technologies. */<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_<wbr>context_quark);<br>
-    if (ctx)<br>
-        ctx->running = FALSE;<br>
-}<br>
-<br>
-static gboolean<br>
-periodic_access_technologies_<wbr>check (MMIfaceModem *self)<br>
-{<br>
-    AccessTechnologiesCheckContext *ctx;<br>
-<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_<wbr>context_quark);<br>
-<br>
-    /* Only launch a new one if not one running already OR if the last one run<br>
-     * was more than 15s ago. */<br>
-    if (!ctx->running) {<br>
-        ctx->running = TRUE;<br>
-        MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies (<br>
-            self,<br>
-            (GAsyncReadyCallback)access_<wbr>technologies_check_ready,<br>
-            NULL);<br>
-    }<br>
-<br>
-    return G_SOURCE_CONTINUE;<br>
-}<br>
-<br>
-void<br>
-mm_iface_modem_refresh_<wbr>access_technologies (MMIfaceModem *self)<br>
-{<br>
-    AccessTechnologiesCheckContext *ctx;<br>
-<br>
-    if (G_UNLIKELY (!access_technologies_check_<wbr>context_quark))<br>
-        access_technologies_check_<wbr>context_quark = (g_quark_from_static_string (<br>
-                                                       ACCESS_TECHNOLOGIES_CHECK_<wbr>CONTEXT_TAG));<br>
-<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_<wbr>context_quark);<br>
-    if (!ctx)<br>
-        return;<br>
-<br>
-    /* Re-set timeout */<br>
-    if (ctx->timeout_source)<br>
-        g_source_remove (ctx->timeout_source);<br>
-    ctx->timeout_source = g_timeout_add_seconds (ACCESS_TECHNOLOGIES_CHECK_<wbr>TIMEOUT_SEC,<br>
-                                                 (GSourceFunc)periodic_access_<wbr>technologies_check,<br>
-                                                 self);<br>
-<br>
-    /* Get first access technology value */<br>
-    periodic_access_technologies_<wbr>check (self);<br>
-}<br>
-<br>
-static void<br>
-periodic_access_technologies_<wbr>check_disable (MMIfaceModem *self)<br>
-{<br>
-    if (G_UNLIKELY (!access_technologies_check_<wbr>context_quark))<br>
-        access_technologies_check_<wbr>context_quark = (g_quark_from_static_string (<br>
-                                                       ACCESS_TECHNOLOGIES_CHECK_<wbr>CONTEXT_TAG));<br>
-<br>
-    /* Clear access technology */<br>
-    mm_iface_modem_update_access_<wbr>technologies (self,<br>
-                                               MM_MODEM_ACCESS_TECHNOLOGY_<wbr>UNKNOWN,<br>
-                                               MM_MODEM_ACCESS_TECHNOLOGY_<wbr>ANY);<br>
-<br>
-    /* Overwriting the data will free the previous context */<br>
-    g_object_set_qdata (G_OBJECT (self),<br>
-                        access_technologies_check_<wbr>context_quark,<br>
-                        NULL);<br>
-<br>
-    mm_dbg ("Periodic access technology checks disabled");<br>
-}<br>
-<br>
-static void<br>
-periodic_access_technologies_<wbr>check_enable (MMIfaceModem *self)<br>
-{<br>
-    AccessTechnologiesCheckContext *ctx;<br>
-<br>
-    if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies ||<br>
-        !MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies_finish) {<br>
-        /* If loading access technology not supported, don't even bother setting up<br>
-         * a timeout */<br>
-        return;<br>
-    }<br>
-<br>
-    if (G_UNLIKELY (!access_technologies_check_<wbr>context_quark))<br>
-        access_technologies_check_<wbr>context_quark = (g_quark_from_static_string (<br>
-                                                       ACCESS_TECHNOLOGIES_CHECK_<wbr>CONTEXT_TAG));<br>
-<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), access_technologies_check_<wbr>context_quark);<br>
-<br>
-    /* If context is already there, we're already enabled */<br>
-    if (ctx) {<br>
-        periodic_access_technologies_<wbr>check (self);<br>
-        return;<br>
-    }<br>
-<br>
-    /* Create context and keep it as object data */<br>
-    mm_dbg ("Periodic access technology checks enabled");<br>
-    ctx = g_new0 (<wbr>AccessTechnologiesCheckContext<wbr>, 1);<br>
-    g_object_set_qdata_full (G_OBJECT (self),<br>
-                             access_technologies_check_<wbr>context_quark,<br>
-                             ctx,<br>
-                             (GDestroyNotify)access_<wbr>technologies_check_context_<wbr>free);<br>
-<br>
-    /* Get first and setup timeout */<br>
-    mm_iface_modem_refresh_access_<wbr>technologies (self);<br>
-}<br>
-<br>
-/****************************<wbr>******************************<wbr>*******************/<br>
-<br>
-typedef struct {<br>
-    time_t last_update;<br>
     guint recent_timeout_source;<br>
 } SignalQualityUpdateContext;<br>
<br>
@@ -1100,20 +953,6 @@ signal_quality_update_context_<wbr>free (SignalQualityUpdateContext *ctx)<br>
     g_free (ctx);<br>
 }<br>
<br>
-static time_t<br>
-get_last_signal_quality_<wbr>update_time (MMIfaceModem *self)<br>
-{<br>
-    SignalQualityUpdateContext *ctx;<br>
-<br>
-    if (G_UNLIKELY (!signal_quality_update_<wbr>context_quark))<br>
-        signal_quality_update_context_<wbr>quark = (g_quark_from_static_string (<br>
-                                                   SIGNAL_QUALITY_UPDATE_CONTEXT_<wbr>TAG));<br>
-<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_update_context_<wbr>quark);<br>
-<br>
-    return (ctx ? ctx->last_update : 0);<br>
-}<br>
-<br>
 static gboolean<br>
 expire_signal_quality (MMIfaceModem *self)<br>
 {<br>
@@ -1187,9 +1026,6 @@ update_signal_quality (MMIfaceModem *self,<br>
             (GDestroyNotify)signal_<wbr>quality_update_context_free);<br>
     }<br>
<br>
-    /* Keep current timestamp */<br>
-    ctx->last_update = time (NULL);<br>
-<br>
     /* Note: we always set the new value, even if the signal quality level<br>
      * is the same, in order to provide an up to date 'recent' flag.<br>
      * The only exception being if 'expire' is FALSE; in that case we assume<br>
@@ -1229,142 +1065,334 @@ mm_iface_modem_update_signal_<wbr>quality (MMIfaceModem *self,<br>
 }<br>
<br>
 /*****************************<wbr>******************************<wbr>******************/<br>
+/* Signal info (quality and access technology) polling */<br>
+<br>
+typedef enum {<br>
+    SIGNAL_CHECK_STEP_NONE,<br>
+    SIGNAL_CHECK_STEP_FIRST,<br>
+    SIGNAL_CHECK_STEP_SIGNAL_<wbr>QUALITY,<br>
+    SIGNAL_CHECK_STEP_ACCESS_<wbr>TECHNOLOGIES,<br>
+    SIGNAL_CHECK_STEP_LAST,<br>
+} SignalCheckStep;<br>
<br>
 typedef struct {<br>
-    guint interval;<br>
-    guint initial_retries;<br>
-    guint timeout_source;<br>
-    gboolean running;<br>
-} SignalQualityCheckContext;<br>
+    gboolean enabled;<br>
+    guint    interval;<br>
+    guint    initial_retries;<br>
+    guint    timeout_source;<br>
+<br>
+    /* Values polled in this iteration */<br>
+    guint                   signal_quality;<br>
+    MMModemAccessTechnology access_technologies;<br>
+    guint                   access_technologies_mask;<br>
+<br>
+    /* If both these are unset we'll automatically stop polling */<br>
+    gboolean signal_quality_polling_<wbr>supported;<br>
+    gboolean access_technology_polling_<wbr>supported;<br>
+<br>
+    /* Steps triggered when polling active */<br>
+    SignalCheckStep running_step;<br>
+} SignalCheckContext;<br>
<br>
 static void<br>
-signal_quality_check_context_<wbr>free (SignalQualityCheckContext *ctx)<br>
+signal_check_context_free (SignalCheckContext *ctx)<br>
 {<br>
     if (ctx->timeout_source)<br>
         g_source_remove (ctx->timeout_source);<br>
-    g_free (ctx);<br>
+    g_slice_free (SignalCheckContext, ctx);<br>
 }<br>
<br>
-static gboolean periodic_signal_quality_check (MMIfaceModem *self);<br>
+static SignalCheckContext *<br>
+get_signal_check_context (MMIfaceModem *self)<br>
+{<br>
+    SignalCheckContext *ctx;<br>
+<br>
+    if (G_UNLIKELY (!signal_check_context_quark))<br>
+        signal_check_context_quark = (g_quark_from_static_string (<br>
+                                          SIGNAL_CHECK_CONTEXT_TAG));<br>
+<br>
+    ctx = g_object_get_qdata (G_OBJECT (self), signal_check_context_quark);<br>
+    if (!ctx) {<br>
+        /* Create context and attach it to the object */<br>
+        ctx = g_slice_new0 (SignalCheckContext);<br>
+        ctx->running_step = SIGNAL_CHECK_STEP_NONE;<br>
+<br>
+        /* Initially assume supported if load_access_technologies() is<br>
+         * implemented. If the plugin reports an UNSUPPORTED error we'll clear<br>
+         * this flag and no longer poll. */<br>
+        ctx->access_technology_<wbr>polling_supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies &&<br>
+                                                    MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies_finish);<br>
+<br>
+        /* Initially assume supported if load_signal_quality() is<br>
+         * implemented. If the plugin reports an UNSUPPORTED error we'll clear<br>
+         * this flag and no longer poll. */<br>
+        ctx->signal_quality_polling_<wbr>supported = (MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality &&<br>
+                                                 MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_<wbr>finish);<br>
+<br>
+        g_object_set_qdata_full (G_OBJECT (self), signal_check_context_quark,<br>
+                                 ctx, (GDestroyNotify) signal_check_context_free);<br>
+    }<br>
+<br>
+    g_assert (ctx);<br>
+    return ctx;<br>
+}<br>
+<br>
+static void     periodic_signal_check_disable (MMIfaceModem *self,<br>
+                                               gboolean      clear);<br>
+static gboolean periodic_signal_check_cb      (MMIfaceModem *self);<br>
+static void     peridic_signal_check_step     (MMIfaceModem *self);<br>
+<br>
+static void<br>
+access_technologies_check_<wbr>ready (MMIfaceModem *self,<br>
+                                 GAsyncResult *res)<br>
+{<br>
+    GError             *error = NULL;<br>
+    SignalCheckContext *ctx;<br>
+<br>
+    ctx = get_signal_check_context (self);<br>
+<br>
+    if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies_finish (<br>
+            self,<br>
+            res,<br>
+            &ctx->access_technologies,<br>
+            &ctx->access_technologies_<wbr>mask,<br>
+            &error)) {<br>
+        /* Did the plugin report that polling access technology is unsupported? */<br>
+        if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {<br>
+            mm_dbg ("Polling to refresh access technologies is unsupported");<br>
+            ctx->access_technology_<wbr>polling_supported = FALSE;<br>
+        } else<br>
+            mm_dbg ("Couldn't refresh access technologies: '%s'", error->message);<br>
+        g_error_free (error);<br>
+    }<br>
+    /* We may have been disabled while this command was running. */<br>
+    else if (ctx->enabled)<br>
+        mm_iface_modem_update_access_<wbr>technologies (self, ctx->access_technologies, ctx->access_technologies_mask)<wbr>;<br>
+<br>
+    /* Go on */<br>
+    ctx->running_step++;<br>
+    peridic_signal_check_step (self);<br>
+}<br>
<br>
 static void<br>
 signal_quality_check_ready (MMIfaceModem *self,<br>
                             GAsyncResult *res)<br>
 {<br>
-    GError *error = NULL;<br>
-    guint signal_quality;<br>
-    SignalQualityCheckContext *ctx;<br>
+    GError             *error = NULL;<br>
+    SignalCheckContext *ctx;<br>
+<br>
+    ctx = get_signal_check_context (self);<br>
<br>
-    signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_<wbr>finish (self,<br>
-                                                                                      res,<br>
-                                                                                      &error);<br>
+    ctx->signal_quality = MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_<wbr>finish (self, res, &error);<br>
     if (error) {<br>
-        mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);<br>
+        /* Did the plugin report that polling signal quality is unsupported? */<br>
+        if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) {<br>
+            mm_dbg ("Polling to refresh signal quality is unsupported");<br>
+            ctx->signal_quality_polling_<wbr>supported = FALSE;<br>
+        } else<br>
+            mm_dbg ("Couldn't refresh signal quality: '%s'", error->message);<br>
         g_error_free (error);<br>
-    } else<br>
-        update_signal_quality (self, signal_quality, TRUE);<br>
-<br>
-    /* Remove the running tag. Note that the context may have been removed by<br>
-     * mm_iface_modem_shutdown when this function is invoked as a callback of<br>
-     * load_signal_quality. */<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_<wbr>quark);<br>
-    if (ctx) {<br>
-        if (ctx->interval == SIGNAL_QUALITY_INITIAL_CHECK_<wbr>TIMEOUT_SEC &&<br>
-            (signal_quality != 0 || --ctx->initial_retries == 0)) {<br>
-            ctx->interval = SIGNAL_QUALITY_CHECK_TIMEOUT_<wbr>SEC;<br>
-            if (ctx->timeout_source) {<br>
-                mm_dbg ("Periodic signal quality checks rescheduled (interval = %ds)", ctx->interval);<br>
-                g_source_remove(ctx->timeout_<wbr>source);<br>
-                ctx->timeout_source = g_timeout_add_seconds (ctx->interval,<br>
-                                                             (GSourceFunc)periodic_signal_<wbr>quality_check,<br>
-                                                             self);<br>
+    }<br>
+    /* We may have been disabled while this command was running. */<br>
+    else if (ctx->enabled)<br>
+        update_signal_quality (self, ctx->signal_quality, TRUE);<br>
+<br>
+    /* Go on */<br>
+    ctx->running_step++;<br>
+    peridic_signal_check_step (self);<br>
+}<br>
+<br>
+static void<br>
+peridic_signal_check_step (MMIfaceModem *self)<br>
+{<br>
+    SignalCheckContext *ctx;<br>
+<br>
+    ctx = get_signal_check_context (self);<br>
+<br>
+    switch (ctx->running_step) {<br>
+    case SIGNAL_CHECK_STEP_NONE:<br>
+        g_assert_not_reached ();<br>
+<br>
+    case SIGNAL_CHECK_STEP_FIRST:<br>
+        /* Fall down to next step */<br>
+        ctx->running_step++;<br>
+<br>
+    case SIGNAL_CHECK_STEP_SIGNAL_<wbr>QUALITY:<br>
+        if (ctx->enabled && ctx->signal_quality_polling_<wbr>supported) {<br>
+            MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (<br>
+                self, (GAsyncReadyCallback)signal_<wbr>quality_check_ready, NULL);<br>
+            return;<br>
+        }<br>
+        /* Fall down to next step */<br>
+        ctx->running_step++;<br>
+<br>
+    case SIGNAL_CHECK_STEP_ACCESS_<wbr>TECHNOLOGIES:<br>
+        if (ctx->enabled && ctx->access_technology_<wbr>polling_supported) {<br>
+            MM_IFACE_MODEM_GET_INTERFACE (self)->load_access_<wbr>technologies (<br>
+                self, (GAsyncReadyCallback)access_<wbr>technologies_check_ready, NULL);<br>
+            return;<br>
+        }<br>
+        /* Fall down to next step */<br>
+        ctx->running_step++;<br>
+<br>
+    case SIGNAL_CHECK_STEP_LAST:<br>
+        /* Flag as sequence finished */<br>
+        ctx->running_step = SIGNAL_CHECK_STEP_NONE;<br>
+<br>
+        /* If we have been disabled while we were running the steps, we don't<br>
+         * do anything else. */<br>
+        if (!ctx->enabled) {<br>
+            mm_dbg ("Periodic signal checks not rescheduled: disabled");<br>
+            return;<br>
+        }<br>
+<br>
+        /* If both tasks are unsupported, implicitly disable. Do NOT clear the<br>
+         * values, because if we're told they are unsupported it may be that<br>
+         * they're really updated via unsolicited messages. */<br>
+        if (!ctx->access_technology_<wbr>polling_supported && !ctx->signal_quality_polling_<wbr>supported) {<br>
+            mm_dbg ("Periodic signal checks not supported");<br>
+            periodic_signal_check_disable (self, FALSE);<br>
+            return;<br>
+        }<br>
+<br>
+        /* Schedule when we poll next time.<br>
+         * Initially we poll at a higher frequency until we get valid signal<br>
+         * quality and access technology values. As soon as we get them, OR if<br>
+         * we made too many retries at a high frequency, we fallback to the<br>
+         * slower polling. */<br>
+        if (ctx->interval == SIGNAL_CHECK_INITIAL_TIMEOUT_<wbr>SEC) {<br>
+            gboolean signal_quality_ready;<br>
+            gboolean access_technology_ready;<br>
+<br>
+            /* Signal quality is ready if unsupported or if we got a valid<br>
+             * value reported */<br>
+            signal_quality_ready = (!ctx->signal_quality_polling_<wbr>supported || (ctx->signal_quality != 0));<br>
+            /* Access technology is ready if unsupported or if we got a valid<br>
+             * value reported */<br>
+            access_technology_ready = (!ctx->access_technology_<wbr>polling_supported ||<br>
+                                       ((ctx->access_technologies & ctx->access_technologies_mask) != MM_MODEM_ACCESS_TECHNOLOGY_<wbr>UNKNOWN));<br>
+<br>
+            if (signal_quality_ready && access_technology_ready) {<br>
+                mm_dbg ("Initial signal quality and access technology ready: fallback to default frequency");<br>
+                ctx->interval = SIGNAL_CHECK_TIMEOUT_SEC;<br>
+            } else if (--ctx->initial_retries == 0) {<br>
+                mm_dbg ("Too many periodic signal checks at high frequency: fallback to default frequency");<br>
+                ctx->interval = SIGNAL_CHECK_TIMEOUT_SEC;<br>
             }<br>
         }<br>
-        ctx->running = FALSE;<br>
+<br>
+        mm_dbg ("Periodic signal quality checks scheduled in %ds", ctx->interval);<br>
+        g_assert (!ctx->timeout_source);<br>
+        ctx->timeout_source = g_timeout_add_seconds (ctx->interval, (GSourceFunc) periodic_signal_check_cb, self);<br>
+        return;<br>
     }<br>
 }<br>
<br>
 static gboolean<br>
-periodic_signal_quality_check (MMIfaceModem *self)<br>
+periodic_signal_check_cb (MMIfaceModem *self)<br>
 {<br>
-    SignalQualityCheckContext *ctx;<br>
+    SignalCheckContext *ctx;<br>
<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_<wbr>quark);<br>
+    ctx = get_signal_check_context (self);<br>
+    g_assert (ctx->enabled);<br>
<br>
-    /* Only launch a new one if not one running already OR if the last one run<br>
-     * was more than 15s ago. */<br>
-    if (!ctx->running ||<br>
-        (time (NULL) - get_last_signal_quality_<wbr>update_time (self) > (ctx->interval / 2))) {<br>
-        ctx->running = TRUE;<br>
-        MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality (<br>
-            self,<br>
-            (GAsyncReadyCallback)signal_<wbr>quality_check_ready,<br>
-            NULL);<br>
-    }<br>
+    /* Start the sequence */<br>
+    ctx->running_step             = SIGNAL_CHECK_STEP_FIRST;<br>
+    ctx->signal_quality           = 0;<br>
+    ctx->access_technologies      = MM_MODEM_ACCESS_TECHNOLOGY_<wbr>UNKNOWN;<br>
+    ctx->access_technologies_mask = MM_MODEM_ACCESS_TECHNOLOGY_<wbr>ANY;<br>
+    peridic_signal_check_step (self);<br>
<br>
-    return G_SOURCE_CONTINUE;<br>
+    /* Remove the timeout and clear the source id */<br>
+    if (ctx->timeout_source)<br>
+        ctx->timeout_source = 0;<br>
+    return G_SOURCE_REMOVE;<br>
 }<br>
<br>
-static void<br>
-periodic_signal_quality_<wbr>check_disable (MMIfaceModem *self)<br>
+void<br>
+mm_iface_modem_refresh_signal (MMIfaceModem *self)<br>
 {<br>
-    if (G_UNLIKELY (!signal_quality_check_<wbr>context_quark))<br>
-        signal_quality_check_context_<wbr>quark = (g_quark_from_static_string (<br>
-                                                  SIGNAL_QUALITY_CHECK_CONTEXT_<wbr>TAG));<br>
+    SignalCheckContext *ctx;<br>
<br>
-    /* Clear signal quality */<br>
-    update_signal_quality (self, 0, FALSE);<br>
+    /* Don't refresh polling if we're not enabled */<br>
+    ctx = get_signal_check_context (self);<br>
+    if (!ctx->enabled) {<br>
+        mm_dbg ("Periodic signal check refresh ignored: checks not enabled");<br>
+        return;<br>
+    }<br>
<br>
-    /* Overwriting the data will free the previous context */<br>
-    g_object_set_qdata (G_OBJECT (self),<br>
-                        signal_quality_check_context_<wbr>quark,<br>
-                        NULL);<br>
+    /* Don't refresh if we're already doing it */<br>
+    if (ctx->running_step != SIGNAL_CHECK_STEP_NONE) {<br>
+        mm_dbg ("Periodic signal check refresh ignored: check already running");<br>
+        return;<br>
+    }<br>
+<br>
+    mm_dbg ("Periodic signal check refresh requested");<br>
+<br>
+    /* Remove the scheduled timeout as we're going to refresh<br>
+     * right away */<br>
+    if (ctx->timeout_source) {<br>
+        g_source_remove (ctx->timeout_source);<br>
+        ctx->timeout_source = 0;<br>
+    }<br>
<br>
-    mm_dbg ("Periodic signal quality checks disabled");<br>
+    /* Start sequence */<br>
+    periodic_signal_check_cb (self);<br>
 }<br>
<br>
 static void<br>
-periodic_signal_quality_<wbr>check_enable (MMIfaceModem *self)<br>
+periodic_signal_check_disable (MMIfaceModem *self,<br>
+                               gboolean      clear)<br>
 {<br>
-    SignalQualityCheckContext *ctx;<br>
+    SignalCheckContext *ctx;<br>
<br>
-    if (!MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality ||<br>
-        !MM_IFACE_MODEM_GET_INTERFACE (self)->load_signal_quality_<wbr>finish) {<br>
-        /* If loading signal quality not supported, don't even bother setting up<br>
-         * a timeout */<br>
+    ctx = get_signal_check_context (self);<br>
+    if (!ctx->enabled)<br>
         return;<br>
+<br>
+    /* Clear access technology and signal quality */<br>
+    if (clear) {<br>
+        update_signal_quality (self, 0, FALSE);<br>
+        mm_iface_modem_update_access_<wbr>technologies (self,<br>
+                                                   MM_MODEM_ACCESS_TECHNOLOGY_<wbr>UNKNOWN,<br>
+                                                   MM_MODEM_ACCESS_TECHNOLOGY_<wbr>ANY);<br>
     }<br>
<br>
-    if (G_UNLIKELY (!signal_quality_check_<wbr>context_quark))<br>
-        signal_quality_check_context_<wbr>quark = (g_quark_from_static_string (<br>
-                                                  SIGNAL_QUALITY_CHECK_CONTEXT_<wbr>TAG));<br>
+    /* Remove scheduled timeout */<br>
+    if (ctx->timeout_source) {<br>
+        g_source_remove (ctx->timeout_source);<br>
+        ctx->timeout_source = 0;<br>
+    }<br>
<br>
-    ctx = g_object_get_qdata (G_OBJECT (self), signal_quality_check_context_<wbr>quark);<br>
+    ctx->enabled = FALSE;<br>
+    mm_dbg ("Periodic signal checks disabled");<br>
+}<br>
<br>
-    /* If context is already there, we're already enabled */<br>
-    if (ctx) {<br>
-        periodic_signal_quality_check (self);<br>
+static void<br>
+periodic_signal_check_enable (MMIfaceModem *self)<br>
+{<br>
+    SignalCheckContext *ctx;<br>
+<br>
+    ctx = get_signal_check_context (self);<br>
+<br>
+    /* If polling access technology and signal quality not supported, don't even<br>
+     * bother trying. */<br>
+    if (!ctx->signal_quality_polling_<wbr>supported && !ctx->access_technology_<wbr>polling_supported) {<br>
+        mm_dbg ("Not enabling periodic signal checks: unsupported");<br>
         return;<br>
     }<br>
<br>
-    /* Create context and keep it as object data */<br>
-    ctx = g_new0 (SignalQualityCheckContext, 1);<br>
-    /* Schedule the signal quality check using a shorter period, up to 5<br>
-     * periods, initially until a non-zero signal quality value is obtained<br>
-     * and then switch back to the normal period. */<br>
-    ctx->interval = SIGNAL_QUALITY_INITIAL_CHECK_<wbr>TIMEOUT_SEC;<br>
-    ctx->initial_retries = 5;<br>
-    mm_dbg ("Periodic signal quality checks enabled (interval = %ds)", ctx->interval);<br>
-    ctx->timeout_source = g_timeout_add_seconds (ctx->interval,<br>
-                                                 (GSourceFunc)periodic_signal_<wbr>quality_check,<br>
-                                                 self);<br>
-    g_object_set_qdata_full (G_OBJECT (self),<br>
-                             signal_quality_check_context_<wbr>quark,<br>
-                             ctx,<br>
-                             (GDestroyNotify)signal_<wbr>quality_check_context_free);<br>
+    /* Log and flag as enabled */<br>
+    if (!ctx->enabled) {<br>
+        mm_dbg ("Periodic signal checks enabled");<br>
+        ctx->enabled = TRUE;<br>
+        /* As soon as it is started, poll at a higher frequency */<br>
+        ctx->interval        = SIGNAL_CHECK_INITIAL_TIMEOUT_<wbr>SEC;<br>
+        ctx->initial_retries = SIGNAL_CHECK_INITIAL_RETRIES;<br>
+    }<br>
<br>
-    /* Get first signal quality value */<br>
-    periodic_signal_quality_check (self);<br>
+    /* And refresh, which will trigger the first check */<br>
+    mm_iface_modem_refresh_signal (self);<br>
 }<br>
<br>
 /*****************************<wbr>******************************<wbr>******************/<br>
@@ -1456,18 +1484,12 @@ __iface_modem_update_state_<wbr>internal (MMIfaceModem *self,<br>
<br>
         /* If we go to a registered/connected state (from unregistered), setup<br>
          * signal quality and access technologies periodic retrieval */<br>
-        if (new_state >= MM_MODEM_STATE_REGISTERED &&<br>
-            old_state < MM_MODEM_STATE_REGISTERED) {<br>
-            periodic_signal_quality_check_<wbr>enable (self);<br>
-            periodic_access_technologies_<wbr>check_enable (self);<br>
-        }<br>
+        if (new_state >= MM_MODEM_STATE_REGISTERED && old_state < MM_MODEM_STATE_REGISTERED)<br>
+            periodic_signal_check_enable (self);<br>
         /* If we go from a registered/connected state to unregistered,<br>
          * cleanup signal quality retrieval */<br>
-        else if (old_state >= MM_MODEM_STATE_REGISTERED &&<br>
-                 new_state < MM_MODEM_STATE_REGISTERED) {<br>
-            periodic_signal_quality_check_<wbr>disable (self);<br>
-            periodic_access_technologies_<wbr>check_disable (self);<br>
-        }<br>
+        else if (old_state >= MM_MODEM_STATE_REGISTERED && new_state < MM_MODEM_STATE_REGISTERED)<br>
+            periodic_signal_check_disable (self, TRUE);<br>
     }<br>
<br>
     if (skeleton)<br>
@@ -4906,14 +4928,9 @@ mm_iface_modem_initialize (MMIfaceModem *self,<br>
 void<br>
 mm_iface_modem_shutdown (MMIfaceModem *self)<br>
 {<br>
-    /* Remove SignalQualityCheckContext object to make sure any pending<br>
-     * invocation of periodic_signal_quality_check is cancelled before<br>
-     * SignalQualityUpdateContext is removed (as signal_quality_check_ready may<br>
-     * call update_signal_quality). */<br>
-    if (G_LIKELY (signal_quality_check_context_<wbr>quark))<br>
-        g_object_set_qdata (G_OBJECT (self),<br>
-                            signal_quality_check_context_<wbr>quark,<br>
-                            NULL);<br>
+    /* Make sure signal polling is disabled. No real need to clear values, as<br>
+     * we're shutting down the interface anyway. */<br>
+    periodic_signal_check_disable (self, FALSE);<br>
<br>
     /* Remove SignalQualityUpdateContext object to make sure any pending<br>
      * invocation of expire_signal_quality is canceled before the DBus skeleton<br>
@@ -4923,14 +4940,6 @@ mm_iface_modem_shutdown (MMIfaceModem *self)<br>
                             signal_quality_update_context_<wbr>quark,<br>
                             NULL);<br>
<br>
-    /* Remove AccessTechnologiesCheckContext object to make sure any pending<br>
-     * invocation of periodic_access_technologies_<wbr>check is canceled before the<br>
-     * DBus skeleton is removed. */<br>
-    if (G_LIKELY (access_technologies_check_<wbr>context_quark))<br>
-        g_object_set_qdata (G_OBJECT (self),<br>
-                            access_technologies_check_<wbr>context_quark,<br>
-                            NULL);<br>
-<br>
     /* Remove running restart initialization idle, if any */<br>
     if (G_LIKELY (restart_initialize_idle_<wbr>quark))<br>
         g_object_set_qdata (G_OBJECT (self),<br>
diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h<br>
index 517c651d..17ded5bc 100644<br>
--- a/src/mm-iface-modem.h<br>
+++ b/src/mm-iface-modem.h<br>
@@ -444,13 +444,13 @@ void mm_iface_modem_update_access_<wbr>technologies (MMIfaceModem *self,<br>
                                                 MMModemAccessTechnology access_tech,<br>
                                                 guint32 mask);<br>
<br>
-/* Allow requesting to refresh access tech */<br>
-void mm_iface_modem_refresh_access_<wbr>technologies (MMIfaceModem *self);<br>
-<br>
 /* Allow updating signal quality */<br>
 void mm_iface_modem_update_signal_<wbr>quality (MMIfaceModem *self,<br>
                                            guint signal_quality);<br>
<br>
+/* Allow requesting to refresh signal via polling */<br>
+void mm_iface_modem_refresh_signal (MMIfaceModem *self);<br>
+<br>
 /* Allow setting allowed modes */<br>
 void     mm_iface_modem_set_current_<wbr>modes        (MMIfaceModem *self,<br>
                                                   MMModemMode allowed,<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.12.2<br>
<br>
______________________________<wbr>_________________<br>
ModemManager-devel mailing list<br>
<a href="mailto:ModemManager-devel@lists.freedesktop.org">ModemManager-devel@lists.<wbr>freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/modemmanager-<wbr>devel</a><br>
</font></span></blockquote></div><br></div>