gstreamer: Fix deadlock when last allocator ref is held by buffer

This deadlock occurs when a buffer is holding the last reference on
the allocator. In gst_libcamera_allocator_release() we must drop the
object lock before dropping the last ref of that object since the
destructor will lock it again causing deadlock.

This was notice while switching camera or resolution in Cheese software.

Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
Nicolas Dufresne 2021-08-26 09:23:44 -04:00 committed by Laurent Pinchart
parent af1f731f47
commit 1ca5513396

View file

@ -108,15 +108,18 @@ gst_libcamera_allocator_release(GstMiniObject *mini_object)
{
GstMemory *mem = GST_MEMORY_CAST(mini_object);
GstLibcameraAllocator *self = GST_LIBCAMERA_ALLOCATOR(mem->allocator);
GLibLocker lock(GST_OBJECT(self));
auto *frame = reinterpret_cast<FrameWrap *>(gst_mini_object_get_qdata(mini_object, FrameWrap::getQuark()));
gst_memory_ref(mem);
{
GLibLocker lock(GST_OBJECT(self));
auto *frame = reinterpret_cast<FrameWrap *>(gst_mini_object_get_qdata(mini_object, FrameWrap::getQuark()));
if (frame->releasePlane()) {
auto *pool = reinterpret_cast<GQueue *>(g_hash_table_lookup(self->pools, frame->stream_));
g_return_val_if_fail(pool, TRUE);
g_queue_push_tail(pool, frame);
gst_memory_ref(mem);
if (frame->releasePlane()) {
auto *pool = reinterpret_cast<GQueue *>(g_hash_table_lookup(self->pools, frame->stream_));
g_return_val_if_fail(pool, TRUE);
g_queue_push_tail(pool, frame);
}
}
/* Keep last in case we are holding on the last allocator ref. */