diff options
author | Wim Taymans <wtaymans@redhat.com> | 2014-07-10 11:32:20 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2014-07-10 11:36:55 +0200 |
commit | 945c93fde09b461d4b810846e2a9443f915e6507 (patch) | |
tree | c3598f6eb9c3bf435d034a3b57f52327bdf2e934 /gst/rtsp-server/rtsp-server.c | |
parent | 6543082d2b6eb75da4bddc5b43aa24e759123fae (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.c | 35 |
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; } |