summaryrefslogtreecommitdiff
path: root/gst/rtsp-server/rtsp-server.c
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2014-07-10 11:32:20 +0200
committerWim Taymans <wtaymans@redhat.com>2014-07-10 11:36:55 +0200
commit945c93fde09b461d4b810846e2a9443f915e6507 (patch)
treec3598f6eb9c3bf435d034a3b57f52327bdf2e934 /gst/rtsp-server/rtsp-server.c
parent6543082d2b6eb75da4bddc5b43aa24e759123fae (diff)
filter: Release lock in filter functions
Release the object lock before calling the filter functions. We need to keep a cookie to detect when the list changed during the filter callback. We also keep a hashtable to make sure we only call the filter function once for each object in case of concurrent modification. Fixes https://bugzilla.gnome.org/show_bug.cgi?id=732950
Diffstat (limited to 'gst/rtsp-server/rtsp-server.c')
-rw-r--r--gst/rtsp-server/rtsp-server.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c
index a5ea95a..84a7d50 100644
--- a/gst/rtsp-server/rtsp-server.c
+++ b/gst/rtsp-server/rtsp-server.c
@@ -90,6 +90,7 @@ struct _GstRTSPServerPrivate
/* the clients that are connected */
GList *clients;
+ guint clients_cookie;
};
#define DEFAULT_ADDRESS "0.0.0.0"
@@ -999,6 +1000,7 @@ unmanage_client (GstRTSPClient * client, ClientContext * ctx)
GST_RTSP_SERVER_LOCK (server);
priv->clients = g_list_remove (priv->clients, ctx);
+ priv->clients_cookie++;
GST_RTSP_SERVER_UNLOCK (server);
if (ctx->thread) {
@@ -1050,6 +1052,7 @@ manage_client (GstRTSPServer * server, GstRTSPClient * client)
g_signal_connect (client, "closed", (GCallback) unmanage_client, cctx);
priv->clients = g_list_prepend (priv->clients, cctx);
+ priv->clients_cookie++;
gst_rtsp_client_attach (client, mainctx);
@@ -1361,38 +1364,62 @@ gst_rtsp_server_client_filter (GstRTSPServer * server,
{
GstRTSPServerPrivate *priv;
GList *result, *walk, *next;
+ GHashTable *visited;
+ guint cookie;
g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
priv = server->priv;
result = NULL;
+ if (func)
+ visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
GST_RTSP_SERVER_LOCK (server);
+restart:
+ cookie = priv->clients_cookie;
for (walk = priv->clients; walk; walk = next) {
ClientContext *cctx = walk->data;
+ GstRTSPClient *client = cctx->client;
GstRTSPFilterResult res;
+ gboolean changed;
next = g_list_next (walk);
- if (func)
- res = func (server, cctx->client, user_data);
- else
+ if (func) {
+ /* only visit each media once */
+ if (g_hash_table_contains (visited, client))
+ continue;
+
+ g_hash_table_add (visited, g_object_ref (client));
+ GST_RTSP_SERVER_UNLOCK (server);
+
+ res = func (server, client, user_data);
+
+ GST_RTSP_SERVER_LOCK (server);
+ } else
res = GST_RTSP_FILTER_REF;
+ changed = (cookie != priv->clients_cookie);
+
switch (res) {
case GST_RTSP_FILTER_REMOVE:
/* remove client, FIXME */
break;
case GST_RTSP_FILTER_REF:
- result = g_list_prepend (result, g_object_ref (cctx->client));
+ result = g_list_prepend (result, g_object_ref (client));
break;
case GST_RTSP_FILTER_KEEP:
default:
break;
}
+ if (changed)
+ goto restart;
}
GST_RTSP_SERVER_UNLOCK (server);
+ if (func)
+ g_hash_table_unref (visited);
+
return result;
}