From 301a094ef9562d2351e30acf100d1c2f23ed94c7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 28 Apr 2017 20:24:36 -0700 Subject: [PATCH] Avoid potential dispmanx_gfx driver lockup The dispmanx driver had a small race wherein if the vsync completed between checking for a free page and waiting on the condvar, it would hang forever waiting for a condition that would never fire. I'm hoping this is what was causing the triple buffering lockups. In my testing with it re-enabled and this fix, things are stable (and much more performant than with triple buffering disabled). --- gfx/drivers/dispmanx_gfx.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gfx/drivers/dispmanx_gfx.c b/gfx/drivers/dispmanx_gfx.c index 96abb92971..33af42720a 100644 --- a/gfx/drivers/dispmanx_gfx.c +++ b/gfx/drivers/dispmanx_gfx.c @@ -104,7 +104,6 @@ struct dispmanx_video /* For threading */ scond_t *vsync_condition; - slock_t *vsync_cond_mutex; slock_t *pending_mutex; unsigned int pageflip_pending; @@ -152,9 +151,10 @@ static struct dispmanx_page *dispmanx_get_free_page(void *data, struct dispmanx_ * wait until a free page is freed by vsync CB. */ if (!page) { - slock_lock(_dispvars->vsync_cond_mutex); - scond_wait(_dispvars->vsync_condition, _dispvars->vsync_cond_mutex); - slock_unlock(_dispvars->vsync_cond_mutex); + slock_lock(_dispvars->pending_mutex); + if (_dispvars->pageflip_pending > 0) + scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); + slock_unlock(_dispvars->pending_mutex); } } @@ -426,7 +426,6 @@ static void *dispmanx_gfx_init(const video_info_t *video, /* Initialize the rest of the mutexes and conditions. */ _dispvars->vsync_condition = scond_new(); - _dispvars->vsync_cond_mutex = slock_new(); _dispvars->pending_mutex = slock_new(); _dispvars->core_width = 0; _dispvars->core_height = 0; @@ -697,7 +696,6 @@ static void dispmanx_gfx_free(void *data) /* Destroy mutexes and conditions. */ slock_free(_dispvars->pending_mutex); - slock_free(_dispvars->vsync_cond_mutex); scond_free(_dispvars->vsync_condition); free(_dispvars);