multihandlesink: Use the monotonic clock for detecting timeouts and connection durations
authorSebastian Dröge <sebastian@centricular.com>
Tue, 4 May 2021 15:09:07 +0000 (18:09 +0300)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Wed, 5 May 2021 16:12:38 +0000 (16:12 +0000)
Otherwise real-time clock changes can wrongly trigger timeouts, or not
cause timeouts to happen in time.

Unfortunately real-time clock times still have to be kept track inside
the elements for the statistics. Switching those over to the monotonic
clock would cause behaviour changes from the application point of view.

The statistics are extended with fields with monotonic times though.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/1137>

gst/tcp/gstmultifdsink.c
gst/tcp/gstmultihandlesink.c
gst/tcp/gstmultihandlesink.h
gst/tcp/gstmultisocketsink.c

index d67f772..dfee742 100644 (file)
@@ -671,7 +671,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
 {
   gboolean more;
   gboolean flushing;
-  GstClockTime now;
+  GstClockTime now, now_monotonic;
   GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
   GstMultiHandleSinkClass *mhsinkclass =
       GST_MULTI_HANDLE_SINK_GET_CLASS (mhsink);
@@ -685,6 +685,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
     gint maxsize;
 
     now = g_get_real_time () * GST_USECOND;
+    now_monotonic = g_get_monotonic_time () * GST_USECOND;
 
     if (!mhclient->sending) {
       /* client is not working on a buffer */
@@ -811,6 +812,7 @@ gst_multi_fd_sink_handle_client_write (GstMultiFdSink * sink,
         /* update stats */
         mhclient->bytes_sent += wrote;
         mhclient->last_activity_time = now;
+        mhclient->last_activity_time_monotonic = now_monotonic;
         mhsink->bytes_served += wrote;
       }
     }
@@ -903,7 +905,7 @@ gst_multi_fd_sink_handle_clients (GstMultiFdSink * sink)
     if (G_UNLIKELY (result == 0)) {
       GstClockTime now;
 
-      now = g_get_real_time () * GST_USECOND;
+      now = g_get_monotonic_time () * GST_USECOND;
 
       CLIENTS_LOCK (mhsink);
       for (clients = mhsink->clients; clients; clients = next) {
@@ -914,7 +916,7 @@ gst_multi_fd_sink_handle_clients (GstMultiFdSink * sink)
         mhclient = (GstMultiHandleClient *) client;
         next = g_list_next (clients);
         if (mhsink->timeout > 0
-            && now - mhclient->last_activity_time > mhsink->timeout) {
+            && now - mhclient->last_activity_time_monotonic > mhsink->timeout) {
           mhclient->status = GST_CLIENT_STATUS_SLOW;
           gst_multi_handle_sink_remove_client_link (mhsink, clients);
         }
index 7fbe2ae..32c6eb5 100644 (file)
@@ -543,9 +543,12 @@ gst_multi_handle_sink_client_init (GstMultiHandleClient * client,
 
   /* update start time */
   client->connect_time = g_get_real_time () * GST_USECOND;
+  client->connect_time_monotonic = g_get_monotonic_time () * GST_USECOND;
   client->disconnect_time = 0;
+  client->disconnect_time_monotonic = 0;
   /* set last activity time to connect time */
   client->last_activity_time = client->connect_time;
+  client->last_activity_time_monotonic = client->connect_time_monotonic;
 }
 
 static void
@@ -807,21 +810,28 @@ gst_multi_handle_sink_get_stats (GstMultiHandleSink * sink,
 
     result = gst_structure_new_empty ("multihandlesink-stats");
 
-    if (mhclient->disconnect_time == 0) {
-      interval = (g_get_real_time () * GST_USECOND) - mhclient->connect_time;
+    if (mhclient->disconnect_time_monotonic == 0) {
+      interval =
+          (g_get_monotonic_time () * GST_USECOND) -
+          mhclient->connect_time_monotonic;
     } else {
-      interval = mhclient->disconnect_time - mhclient->connect_time;
+      interval =
+          mhclient->disconnect_time_monotonic -
+          mhclient->connect_time_monotonic;
     }
 
     gst_structure_set (result,
         "bytes-sent", G_TYPE_UINT64, mhclient->bytes_sent,
         "connect-time", G_TYPE_UINT64, mhclient->connect_time,
-        "disconnect-time", G_TYPE_UINT64, mhclient->disconnect_time,
-        "connect-duration", G_TYPE_UINT64, interval,
-        "last-activity-time", G_TYPE_UINT64, mhclient->last_activity_time,
-        "buffers-dropped", G_TYPE_UINT64, mhclient->dropped_buffers,
-        "first-buffer-ts", G_TYPE_UINT64, mhclient->first_buffer_ts,
-        "last-buffer-ts", G_TYPE_UINT64, mhclient->last_buffer_ts, NULL);
+        "connect-time-monotonic", G_TYPE_UINT64,
+        mhclient->connect_time_monotonic, "disconnect-time", G_TYPE_UINT64,
+        mhclient->disconnect_time, "disconnect-time-monotonic", G_TYPE_UINT64,
+        mhclient->disconnect_time_monotonic, "connect-duration", G_TYPE_UINT64,
+        interval, "last-activity-time-monotonic", G_TYPE_UINT64,
+        mhclient->last_activity_time_monotonic, "buffers-dropped",
+        G_TYPE_UINT64, mhclient->dropped_buffers, "first-buffer-ts",
+        G_TYPE_UINT64, mhclient->first_buffer_ts, "last-buffer-ts",
+        G_TYPE_UINT64, mhclient->last_buffer_ts, NULL);
   }
 
 noclient:
@@ -891,6 +901,7 @@ gst_multi_handle_sink_remove_client_link (GstMultiHandleSink * sink,
   mhsinkclass->hash_removing (sink, mhclient);
 
   mhclient->disconnect_time = g_get_real_time () * GST_USECOND;
+  mhclient->disconnect_time_monotonic = g_get_monotonic_time () * GST_USECOND;
 
   /* free client buffers */
   g_slist_foreach (mhclient->sending, (GFunc) gst_mini_object_unref, NULL);
@@ -1652,7 +1663,7 @@ gst_multi_handle_sink_queue_buffer (GstMultiHandleSink * mhsink,
   }
 
   max_buffer_usage = 0;
-  now = g_get_real_time () * GST_USECOND;
+  now = g_get_monotonic_time () * GST_USECOND;
 
   /* now check for new or slow clients */
 restart:
@@ -1670,7 +1681,8 @@ restart:
     /* check hard max and timeout, remove client */
     if ((max_buffers > 0 && mhclient->bufpos >= max_buffers) ||
         (mhsink->timeout > 0
-            && now - mhclient->last_activity_time > mhsink->timeout)) {
+            && now - mhclient->last_activity_time_monotonic >
+            mhsink->timeout)) {
       /* remove client */
       GST_WARNING_OBJECT (sink, "%s client %p is too slow, removing",
           mhclient->debug, mhclient);
index 9dfabee..01ee54a 100644 (file)
@@ -163,8 +163,11 @@ typedef struct {
   /* stats */
   guint64 bytes_sent;
   guint64 connect_time;
+  guint64 connect_time_monotonic;
   guint64 disconnect_time;
+  guint64 disconnect_time_monotonic;
   guint64 last_activity_time;
+  guint64 last_activity_time_monotonic;
   guint64 dropped_buffers;
   guint64 avg_queue_size;
   guint64 first_buffer_ts;
index 81a4543..0031fac 100644 (file)
@@ -825,7 +825,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
 {
   gboolean more;
   gboolean flushing;
-  GstClockTime now;
+  GstClockTime now, now_monotonic;
   GError *err = NULL;
   GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
   GstMultiHandleClient *mhclient = (GstMultiHandleClient *) client;
@@ -834,6 +834,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
 
 
   now = g_get_real_time () * GST_USECOND;
+  now_monotonic = g_get_monotonic_time () * GST_USECOND;
 
   flushing = mhclient->status == GST_CLIENT_STATUS_FLUSHING;
 
@@ -951,6 +952,7 @@ gst_multi_socket_sink_handle_client_write (GstMultiSocketSink * sink,
         /* update stats */
         mhclient->bytes_sent += wrote;
         mhclient->last_activity_time = now;
+        mhclient->last_activity_time_monotonic = now_monotonic;
         mhsink->bytes_served += wrote;
       }
     }
@@ -1115,7 +1117,7 @@ gst_multi_socket_sink_timeout (GstMultiSocketSink * sink)
   GList *clients;
   GstMultiHandleSink *mhsink = GST_MULTI_HANDLE_SINK (sink);
 
-  now = g_get_real_time () * GST_USECOND;
+  now = g_get_monotonic_time () * GST_USECOND;
 
   CLIENTS_LOCK (mhsink);
   for (clients = mhsink->clients; clients; clients = clients->next) {
@@ -1125,7 +1127,7 @@ gst_multi_socket_sink_timeout (GstMultiSocketSink * sink)
     client = clients->data;
     mhclient = (GstMultiHandleClient *) client;
     if (mhsink->timeout > 0
-        && now - mhclient->last_activity_time > mhsink->timeout) {
+        && now - mhclient->last_activity_time_monotonic > mhsink->timeout) {
       mhclient->status = GST_CLIENT_STATUS_SLOW;
       gst_multi_handle_sink_remove_client_link (mhsink, clients);
     }