fix: serialize concurrent GBM buffer allocation in dup_gst_memory_as_dmabuf to prevent SIGSEGV in libgallium with multiple concurrent video pipelines - #522
Open
Elgen69 wants to merge 1 commit into
Conversation
…dmabuf to prevent SIGSEGV in libgallium with multiple concurrent video pipelines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
flutter-pisegfaults intermittently when running multiple concurrentflutterpi_gstreamer_video_playerinstances on software-decoded(non-DMA-BUF) video sources — e.g. 3 zones each playing their own H.264
clip via
avdec_h264on a Raspberry Pi 5. Crash timing is wildlyinconsistent across otherwise-identical runs (observed anywhere from ~5s
to ~60s+ before crashing).
Root cause
dup_gst_memory_as_dmabuf()insrc/plugins/gstreamer_video_player/frame.cruns on a per-pipeline GStreamer worker thread (one thread per zone/pipeline,
e.g.
multiqueue0:src,multiqueue1:src,multiqueue2:src). When thedecoded GstMemory isn't already a DMA-BUF, this function calls
gbm_bo_create()/gbm_bo_map()/gbm_bo_get_fd()to manually copy theframe into a new GBM buffer.
With multiple concurrent zones, multiple threads can call into this
function — and therefore into Mesa's GBM/Gallium3D driver — concurrently,
on the same shared
gbm_device, with no synchronization. Mesa's Galliumdriver is not safe against unsynchronized concurrent calls into the same
GBM device from multiple threads, and this reliably segfaults inside
libgallium.so.Confirmed via
gdb(built with-DCMAKE_BUILD_TYPE=Debug):"Thread 16 "multiqueue0:src" received signal SIGSEGV, Segmentation fault.
0x00007ffff5a6881c in ??? () from /lib/aarch64-linux-gnu/libgallium-25.0.7-2+rpt4.so
#0 ??? () from libgallium-25.0.7-2+rpt4.so
#1 ??? () from /usr/lib/aarch64-linux-gnu/gbm/dri_gbm.so
#2 dup_gst_memory_as_dmabuf (gbm_device=0x5265b0, memory=0x7fff4cf24010)
at src/plugins/gstreamer_video_player/frame.c:433
#3 get_plane_infos (buffer=0x7fffa801e610, info=0x7ac048, gbm_device=0x5265b0, plane_infos=0x7fffb67cc9a8)
at src/plugins/gstreamer_video_player/frame.c:652
#4 frame_new (interface=0xb03b70, sample=0x7fffa00c9f20, info=0x7ac048)
at src/plugins/gstreamer_video_player/frame.c:896
#5 on_appsink_new_sample (appsink=0xaab640 [GstAppSink|sink], userdata=0x7abe60)
at src/plugins/gstreamer_video_player/player.c:806"
I checked whether any existing lock in the file covers this path
(
grep -n "mutex\|lock\|pthread" frame.c) — the only existing lock(
context_lockinstruct frame_interface) guards a different, unrelatedsection of code (EGL context state), not the GBM allocation calls.
This also explains other symptoms I saw during testing: crashes following
closely-timed loop-restarts across zones (loop restart = fresh
decode/frame-callback burst on that zone's thread = higher collision odds
with another zone's simultaneous frame callback), and unreliable
simultaneous zone startup (same race, triggering during initial frame
delivery instead of a loop restart).
Fix
Added a dedicated
pthread_mutex_t gbm_lock, serializing access to thegbm_bo_create()/gbm_bo_map()/gbm_bo_get_fd()sequence insidedup_gst_memory_as_dmabuf(). Locked right after the (safe, non-GBM)gst_memory_map()call, unlocked on every exit path (success and bothfailure paths), following the same locking pattern already used elsewhere
in this file (
context_lockviaDEFINE_LOCK_OPS).Scope is deliberately minimal — this only touches
dup_gst_memory_as_dmabuf();the sibling function
dup_gst_buffer_range_as_dmabuf()(used for adifferent code path) is untouched, since it wasn't the one that crashed in
my reproduction, though it likely has the same class of issue and may be
worth locking too in a follow-up if confirmed.
Testing
Reproduced reliably on:
flutterpi_gstreamer_video_playerzones, each playing aseparate H.264 file via software decode (
avdec_h264)--videomode 1920x1080@60Before fix: segfault within 5–60s, every run, reproducible across many
attempts.
After fix: ran stably well past the ~60s ceiling every prior attempt
had hit, no crashes observed across multiple retest runs (including under
sustained load, ~50°C).