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.
This commit is contained in:
Tim-Philipp Müller 2014-06-24 01:15:25 +01:00
parent fa3ef2e54c
commit 54a9a436ba
2 changed files with 23 additions and 1 deletions

View file

@ -1665,6 +1665,13 @@ gst_multiudpsink_add_internal (GstMultiUDPSink * sink, const gchar * host,
find = g_list_find_custom (sink->clients, &udpclient, find = g_list_find_custom (sink->clients, &udpclient,
(GCompareFunc) client_compare); (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) { if (find) {
client = (GstUDPClient *) find->data; client = (GstUDPClient *) find->data;
@ -1795,13 +1802,22 @@ gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
else else
--sink->num_v6_unique; --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 */ /* Unlock to emit signal before we delete the actual client */
g_mutex_unlock (&sink->client_lock); g_mutex_unlock (&sink->client_lock);
g_signal_emit (G_OBJECT (sink), g_signal_emit (G_OBJECT (sink),
gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED], 0, host, port); gst_multiudpsink_signals[SIGNAL_CLIENT_REMOVED], 0, host, port);
g_mutex_lock (&sink->client_lock); 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); 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, find = g_list_find_custom (sink->clients, &udpclient,
(GCompareFunc) client_compare); (GCompareFunc) client_compare);
if (!find)
find = g_list_find_custom (sink->clients_to_be_removed, &udpclient,
(GCompareFunc) client_compare);
if (!find) if (!find)
goto not_found; goto not_found;

View file

@ -90,6 +90,7 @@ struct _GstMultiUDPSink {
guint num_v4_all; /* number IPv4 clients (including duplicates) */ guint num_v4_all; /* number IPv4 clients (including duplicates) */
guint num_v6_unique; /* number IPv6 clients (excluding duplicates) */ guint num_v6_unique; /* number IPv6 clients (excluding duplicates) */
guint num_v6_all; /* number IPv6 clients (including duplicates) */ guint num_v6_all; /* number IPv6 clients (including duplicates) */
GList *clients_to_be_removed;
/* pre-allocated scrap space for render function */ /* pre-allocated scrap space for render function */
GOutputVector *vec; GOutputVector *vec;