summaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
authorTim-Philipp Müller <tim@centricular.com>2014-06-24 01:15:25 +0100
committerTim-Philipp Müller <tim@centricular.com>2014-12-16 20:26:36 +0000
commit54a9a436ba04e47000300377f899a5d3858c74d8 (patch)
tree96c3dcca5cd79e2c3d5d44559d321c6ac9c3c3ff /gst
parentfa3ef2e54ceb7437368dd6c61ef4531adc3068dd (diff)
multiudpsink: keep client list consistent during removals
We unlock and re-lock the client lock while emitting the removed signal, which causes inconsistencies in the client list vs. the client counts. Instead, remove the client from the list already before emitting the signal and put it into a temporary list of clients to be removed. That way things look consistent to the streaming thread, but signal callbacks can still do things like get stats from removed clients.
Diffstat (limited to 'gst')
-rw-r--r--gst/udp/gstmultiudpsink.c23
-rw-r--r--gst/udp/gstmultiudpsink.h1
2 files changed, 23 insertions, 1 deletions
diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c
index 52099cd0a..c803eabf2 100644
--- a/gst/udp/gstmultiudpsink.c
+++ b/gst/udp/gstmultiudpsink.c
@@ -1665,6 +1665,13 @@ gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
find = g_list_find_custom (sink->clients, &udpclient,
(GCompareFunc) client_compare);
+ if (!find) {
+ find = g_list_find_custom (sink->clients_to_be_removed, &udpclient,
+ (GCompareFunc) client_compare);
+ if (find)
+ gst_udp_client_ref (find->data);
+ }
+
if (find) {
client = (GstUDPClient *) find->data;
@@ -1795,13 +1802,22 @@ gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
else
--sink->num_v6_unique;
+ /* Keep state consistent for streaming thread, so remove from client list,
+ * but keep it around until after the signal has been emitted, in case a
+ * callback wants to get stats for that client or so */
+ sink->clients = g_list_delete_link (sink->clients, find);
+
+ sink->clients_to_be_removed =
+ g_list_prepend (sink->clients_to_be_removed, client);
+
/* Unlock to emit signal before we delete the actual client */
g_mutex_unlock (&sink->client_lock);
g_signal_emit (G_OBJECT (sink),
gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED], 0, host, port);
g_mutex_lock (&sink->client_lock);
- sink->clients = g_list_delete_link (sink->clients, find);
+ sink->clients_to_be_removed =
+ g_list_remove (sink->clients_to_be_removed, client);
gst_udp_client_unref (client);
}
@@ -1860,6 +1876,11 @@ gst_multiudpsink_get_stats (GstMultiUDPSink * sink, const gchar * host,
find = g_list_find_custom (sink->clients, &udpclient,
(GCompareFunc) client_compare);
+
+ if (!find)
+ find = g_list_find_custom (sink->clients_to_be_removed, &udpclient,
+ (GCompareFunc) client_compare);
+
if (!find)
goto not_found;
diff --git a/gst/udp/gstmultiudpsink.h b/gst/udp/gstmultiudpsink.h
index f443dd9f9..19d27285d 100644
--- a/gst/udp/gstmultiudpsink.h
+++ b/gst/udp/gstmultiudpsink.h
@@ -90,6 +90,7 @@ struct _GstMultiUDPSink {
guint num_v4_all; /* number IPv4 clients (including duplicates) */
guint num_v6_unique; /* number IPv6 clients (excluding duplicates) */
guint num_v6_all; /* number IPv6 clients (including duplicates) */
+ GList *clients_to_be_removed;
/* pre-allocated scrap space for render function */
GOutputVector *vec;