From 3c5bb4bf5d0c9f6b5dc3fd1b02e15d8c3759dfb9 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 2 Apr 2024 12:22:33 +1100 Subject: [PATCH] glbufferpool: protect release_buffer from multiple concurrent access If two different threads attempt to release buffers at the same time, then the keep-alive-slightly-longer GQueue may become corrupted. Guard against that with some locking. Part-of: --- .../gst-libs/gst/gl/gstglbufferpool.c | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c index 757fc6a07b..f0dfda7873 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/gl/gstglbufferpool.c @@ -293,11 +293,19 @@ gst_gl_buffer_pool_stop (GstBufferPool * pool) GstGLBufferPool *glpool = GST_GL_BUFFER_POOL_CAST (pool); GstGLBufferPoolPrivate *priv = glpool->priv; GstBuffer *buffer; + GQueue *free_buffers; - while ((buffer = g_queue_pop_head (priv->free_cache_buffers))) { + GST_OBJECT_LOCK (pool); + free_buffers = priv->free_cache_buffers; + priv->free_cache_buffers = g_queue_new (); + GST_OBJECT_UNLOCK (pool); + + while ((buffer = g_queue_pop_head (free_buffers))) { GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, buffer); } + g_clear_pointer (&free_buffers, g_queue_free); + return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool); } @@ -345,18 +353,35 @@ gst_gl_buffer_pool_release_buffer (GstBufferPool * pool, GstBuffer * buffer) GstGLBufferPool *glpool = GST_GL_BUFFER_POOL_CAST (pool); GstGLBufferPoolPrivate *priv = glpool->priv; + GST_OBJECT_LOCK (pool); + if (priv->free_queue_min_depth == 0 - && g_queue_get_length (priv->free_cache_buffers) == 0) { + && g_queue_is_empty (priv->free_cache_buffers)) { + GST_OBJECT_UNLOCK (pool); + GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, buffer); } else { + GPtrArray *free_buffers = g_ptr_array_new (); + guint q_len = g_queue_get_length (priv->free_cache_buffers); + guint i; + g_queue_push_tail (priv->free_cache_buffers, buffer); - while (g_queue_get_length (priv->free_cache_buffers) > - priv->free_queue_min_depth) { + while (q_len > priv->free_queue_min_depth) { GstBuffer *release_buffer = g_queue_pop_head (priv->free_cache_buffers); + g_ptr_array_add (free_buffers, release_buffer); + q_len -= 1; + } + + GST_OBJECT_UNLOCK (pool); + + for (i = 0; i < free_buffers->len; i++) { + GstBuffer *release_buffer = g_ptr_array_index (free_buffers, i); GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (pool, release_buffer); } + + g_ptr_array_unref (free_buffers); } }