From 4fa8f33b92a44fe928817a81653f135402192cac Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 20 Sep 2019 16:43:17 +0200 Subject: client API, vo_libmpv: document random deadlock problems I guess trying to make DR work on libmpv was a mistake. I never observed such a deadlock, but it's looks like it's theoretically possible. --- libmpv/render.h | 4 ++++ video/out/vo_libmpv.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/libmpv/render.h b/libmpv/render.h index 086b42d1b5..6d594e0c06 100644 --- a/libmpv/render.h +++ b/libmpv/render.h @@ -85,6 +85,10 @@ extern "C" { * requirement always existed. Not honoring it will lead to UB (deadlocks, * use of invalid pthread_t handles). This requirement might be removed in * the future, but will require some considerable work internal to libmpv. + * You can avoid this issue by setting "vd-lavc-dr" to "no". + * - MPV_RENDER_PARAM_ADVANCED_CONTROL has some other libmpv-internal problems, + * which may result in random deadlocks (see top of vo_libmpv.c). + * You can probably avoid this issue by setting "vd-lavc-dr" to "no". * * libmpv functions which are safe to call from a render thread are: * - functions marked with "Safe to be called from mpv render API threads." diff --git a/video/out/vo_libmpv.c b/video/out/vo_libmpv.c index 3f3127cb2a..b6c4d9fb06 100644 --- a/video/out/vo_libmpv.c +++ b/video/out/vo_libmpv.c @@ -45,6 +45,22 @@ * > mpv_render_context.update_lock * And: render thread > VO (wait for present) * VO > render thread (wait for present done, via timeout) + * + * Inherent locking bugs with advanced_control: + * + * In theory, it can deadlock on ctx->lock. Consider if the VO thread calls + * forget_frames(), which it does under ctx->lock (e.g. VOCTRL_RESET). + * If a frame was a DR image, dr_helper.c will call mp_dispatch_run(). + * This in turn will call the wakeup callback set with + * mpv_render_context_set_update_callback(). The API user will eventually + * call mpv_render_context_update(), which performs the dispatch queue work + * queued by dr_helper.c. + * And then the function tries to acquire ctx->lock. This can deadlock + * under specific circumstances. It will _not_ deadlock if the queued work + * made the caller release the lock. However, if the caller made queue + * some more work (like freeing a second frame), and will keep the lock + * until it gets a reply. Both threads will wait on each other, and no + * progress can be made. */ struct vo_priv { -- cgit v1.2.3