[PATCH 5/6] base-bearer: setup periodic stats loading

Aleksander Morgado aleksander at aleksander.es
Fri Nov 27 05:51:18 PST 2015


If the bearer implementation supports it, load stats periodically. By default
every 30s for now.
---
 src/mm-base-bearer.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/mm-base-bearer.h |  16 +++++--
 2 files changed, 133 insertions(+), 6 deletions(-)

diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c
index 1b1c7b3..117f144 100644
--- a/src/mm-base-bearer.c
+++ b/src/mm-base-bearer.c
@@ -13,7 +13,8 @@
  * Copyright (C) 2008 - 2009 Novell, Inc.
  * Copyright (C) 2009 - 2011 Red Hat, Inc.
  * Copyright (C) 2011 Google, Inc.
- * Copyright (C) 2011 - 2014 Aleksander Morgado <aleksander at aleksander.es>
+ * Copyright (C) 2015 Azimut Electronics
+ * Copyright (C) 2011 - 2015 Aleksander Morgado <aleksander at aleksander.es>
  */
 
 #include <config.h>
@@ -36,13 +37,16 @@
 #include "mm-base-modem.h"
 #include "mm-log.h"
 #include "mm-modem-helpers.h"
+#include "mm-bearer-stats.h"
 
 /* We require up to 20s to get a proper IP when using PPP */
 #define BEARER_IP_TIMEOUT_DEFAULT 20
 
 #define BEARER_DEFERRED_UNREGISTRATION_TIMEOUT 15
 
-G_DEFINE_TYPE (MMBaseBearer, mm_base_bearer, MM_GDBUS_TYPE_BEARER_SKELETON);
+#define BEARER_STATS_UPDATE_TIMEOUT 30
+
+G_DEFINE_TYPE (MMBaseBearer, mm_base_bearer, MM_GDBUS_TYPE_BEARER_SKELETON)
 
 typedef enum {
     CONNECTION_FORBIDDEN_REASON_NONE,
@@ -97,6 +101,13 @@ struct _MMBaseBearerPrivate {
     /* Handler IDs for the registration state change signals */
     guint id_cdma1x_registration_change;
     guint id_evdo_registration_change;
+
+    /* The stats object to expose */
+    MMBearerStats *stats;
+    /* Handler id for the stats update timeout */
+    guint stats_update_id;
+    /* Timer to measure the duration of the connection */
+    GTimer *duration_timer;
 };
 
 /*****************************************************************************/
@@ -125,6 +136,102 @@ mm_base_bearer_export (MMBaseBearer *self)
 /*****************************************************************************/
 
 static void
+bearer_update_interface_stats (MMBaseBearer *self)
+{
+    mm_gdbus_bearer_set_stats (
+        MM_GDBUS_BEARER (self),
+        mm_bearer_stats_get_dictionary (self->priv->stats));
+}
+
+static void
+bearer_reset_interface_stats (MMBaseBearer *self)
+{
+    g_clear_object (&self->priv->stats);
+    mm_gdbus_bearer_set_stats (MM_GDBUS_BEARER (self), NULL);
+}
+
+static void
+bearer_stats_stop (MMBaseBearer *self)
+{
+    if (self->priv->duration_timer) {
+        if (self->priv->stats)
+            mm_bearer_stats_set_duration (self->priv->stats, (guint64) g_timer_elapsed (self->priv->duration_timer, NULL));
+        g_timer_destroy (self->priv->duration_timer);
+        self->priv->duration_timer = NULL;
+    }
+
+    if (self->priv->stats_update_id) {
+        g_source_remove (self->priv->stats_update_id);
+        self->priv->stats_update_id = 0;
+    }
+}
+
+static void
+reload_stats_ready (MMBaseBearer *self,
+                    GAsyncResult *res)
+{
+    GError *error = NULL;
+    guint64 bytes_rx = 0;
+    guint64 bytes_tx = 0;
+
+    if (!MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish (self, &bytes_rx, &bytes_tx, res, &error)) {
+        g_warning ("Reloading stats failed: %s", error->message);
+        g_error_free (error);
+        return;
+    }
+
+    /* We only update stats if they were retrieved properly */
+    mm_bearer_stats_set_duration (self->priv->stats, (guint32) g_timer_elapsed (self->priv->duration_timer, NULL));
+    mm_bearer_stats_set_bytes_tx (self->priv->stats, bytes_rx);
+    mm_bearer_stats_set_bytes_rx (self->priv->stats, bytes_tx);
+    bearer_update_interface_stats (self);
+}
+
+static gboolean
+stats_update_cb (MMBaseBearer *self)
+{
+    /* If the implementation knows how to update stat values, run it */
+    if (MM_BASE_BEARER_GET_CLASS (self)->reload_stats &&
+        MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish) {
+        MM_BASE_BEARER_GET_CLASS (self)->reload_stats (
+            self,
+            (GAsyncReadyCallback)reload_stats_ready,
+            NULL);
+        return TRUE;
+    }
+
+    /* Otherwise, just update duration and we're done */
+    mm_bearer_stats_set_duration (self->priv->stats, (guint32) g_timer_elapsed (self->priv->duration_timer, NULL));
+    mm_bearer_stats_set_bytes_tx (self->priv->stats, 0);
+    mm_bearer_stats_set_bytes_rx (self->priv->stats, 0);
+    bearer_update_interface_stats (self);
+    return TRUE;
+}
+
+static void
+bearer_stats_start (MMBaseBearer *self)
+{
+    /* Allocate new stats object. If there was one already created from a
+     * previous run, deallocate it */
+    g_assert (!self->priv->stats);
+    self->priv->stats = mm_bearer_stats_new ();
+
+    /* Start duration timer */
+    g_assert (!self->priv->duration_timer);
+    self->priv->duration_timer = g_timer_new ();
+
+    /* Schedule */
+    g_assert (!self->priv->stats_update_id);
+    self->priv->stats_update_id = g_timeout_add_seconds (BEARER_STATS_UPDATE_TIMEOUT,
+                                                         (GSourceFunc) stats_update_cb,
+                                                         self);
+    /* Load initial values */
+    stats_update_cb (self);
+}
+
+/*****************************************************************************/
+
+static void
 bearer_reset_interface_status (MMBaseBearer *self)
 {
     mm_gdbus_bearer_set_connected (MM_GDBUS_BEARER (self), FALSE);
@@ -151,8 +258,11 @@ bearer_update_status (MMBaseBearer *self,
 
     /* Ensure that we don't expose any connection related data in the
      * interface when going into disconnected state. */
-    if (self->priv->status == MM_BEARER_STATUS_DISCONNECTED)
+    if (self->priv->status == MM_BEARER_STATUS_DISCONNECTED) {
         bearer_reset_interface_status (self);
+        /* Stop statistics */
+        bearer_stats_stop (self);
+    }
 }
 
 static void
@@ -171,6 +281,9 @@ bearer_update_status_connected (MMBaseBearer *self,
         MM_GDBUS_BEARER (self),
         mm_bearer_ip_config_get_dictionary (ipv6_config));
 
+    /* Start statistics */
+    bearer_stats_start (self);
+
     /* Update the property value */
     self->priv->status = MM_BEARER_STATUS_CONNECTED;
     g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATUS]);
@@ -590,6 +703,7 @@ mm_base_bearer_connect (MMBaseBearer *self,
     mm_dbg ("Connecting bearer '%s'", self->priv->path);
     self->priv->connect_cancellable = g_cancellable_new ();
     bearer_update_status (self, MM_BEARER_STATUS_CONNECTING);
+    bearer_reset_interface_stats (self);
     MM_BASE_BEARER_GET_CLASS (self)->connect (
         self,
         self->priv->connect_cancellable,
@@ -1150,6 +1264,9 @@ dispose (GObject *object)
 {
     MMBaseBearer *self = MM_BASE_BEARER (object);
 
+    bearer_stats_stop (self);
+    g_clear_object (&self->priv->stats);
+
     if (self->priv->connection) {
         base_bearer_dbus_unexport (self);
         g_clear_object (&self->priv->connection);
diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h
index 2c196f6..58954d4 100644
--- a/src/mm-base-bearer.h
+++ b/src/mm-base-bearer.h
@@ -10,10 +10,10 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details:
  *
- * Author: Aleksander Morgado <aleksander at lanedo.com>
- *
+
  * Copyright (C) 2011 Google, Inc.
- * Copyright (C) 2011 - 2013 Aleksander Morgado <aleksander at gnu.org>
+ * Copyright (C) 2015 Azimut Electronics
+ * Copyright (C) 2011 - 2015 Aleksander Morgado <aleksander at aleksander.es>
  */
 
 #ifndef MM_BASE_BEARER_H
@@ -101,6 +101,16 @@ struct _MMBaseBearerClass {
                                     GAsyncResult *res,
                                     GError **error);
 
+    /* Reload statistics */
+    void (* reload_stats) (MMBaseBearer *bearer,
+                           GAsyncReadyCallback callback,
+                           gpointer user_data);
+    gboolean (* reload_stats_finish) (MMBaseBearer *bearer,
+                                      guint64 *bytes_rx,
+                                      guint64 *bytes_tx,
+                                      GAsyncResult *res,
+                                      GError **error);
+
     /* Report connection status of this bearer */
     void (* report_connection_status) (MMBaseBearer *bearer,
                                        MMBearerConnectionStatus status);
-- 
2.6.2



More information about the ModemManager-devel mailing list