From 5a65f5f3b77fcb5186e5aea7873678ec72989c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 4 May 2021 18:09:07 +0300 Subject: [PATCH] multihandlesink: Use the monotonic clock for detecting timeouts and connection durations 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: --- gst/tcp/gstmultifdsink.c | 8 +++++--- gst/tcp/gstmultihandlesink.c | 34 +++++++++++++++++++++++----------- gst/tcp/gstmultihandlesink.h | 3 +++ gst/tcp/gstmultisocketsink.c | 8 +++++--- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/gst/tcp/gstmultifdsink.c b/gst/tcp/gstmultifdsink.c index d67f772868..dfee7420eb 100644 --- a/gst/tcp/gstmultifdsink.c +++ b/gst/tcp/gstmultifdsink.c @@ -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); } diff --git a/gst/tcp/gstmultihandlesink.c b/gst/tcp/gstmultihandlesink.c index 7fbe2ae3a9..32c6eb50a0 100644 --- a/gst/tcp/gstmultihandlesink.c +++ b/gst/tcp/gstmultihandlesink.c @@ -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 @@ gst_multi_handle_sink_queue_buffer (GstMultiHandleSink * mhsink, /* 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); diff --git a/gst/tcp/gstmultihandlesink.h b/gst/tcp/gstmultihandlesink.h index 9dfabee880..01ee54a773 100644 --- a/gst/tcp/gstmultihandlesink.h +++ b/gst/tcp/gstmultihandlesink.h @@ -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; diff --git a/gst/tcp/gstmultisocketsink.c b/gst/tcp/gstmultisocketsink.c index 81a4543c8c..0031fac93b 100644 --- a/gst/tcp/gstmultisocketsink.c +++ b/gst/tcp/gstmultisocketsink.c @@ -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); }