From 127e56780a82fdc529428d4b13ffb5748b28716e Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 9 Feb 2018 08:42:39 +0100 Subject: [PATCH] Fix deadlock on exit if SKIP_FRAMES disabled On exit, the renderer will not consume frames anymore, so signal the condition variable to wake up the decoder. --- app/src/decoder.c | 4 ++++ app/src/decoder.h | 1 + app/src/frames.c | 24 ++++++++++++++++++------ app/src/frames.h | 4 ++++ app/src/scrcpy.c | 1 + 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 561d2dfe..480b3617 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -152,6 +152,10 @@ SDL_bool decoder_start(struct decoder *decoder) { return SDL_TRUE; } +void decoder_stop(struct decoder *decoder) { + frames_stop(decoder->frames); +} + void decoder_join(struct decoder *decoder) { SDL_WaitThread(decoder->thread, NULL); } diff --git a/app/src/decoder.h b/app/src/decoder.h index 9c07ab22..59a59d75 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -14,6 +14,7 @@ struct decoder { }; SDL_bool decoder_start(struct decoder *decoder); +void decoder_stop(struct decoder *decoder); void decoder_join(struct decoder *decoder); #endif diff --git a/app/src/frames.c b/app/src/frames.c index 7025a830..a9aec3d4 100644 --- a/app/src/frames.c +++ b/app/src/frames.c @@ -27,6 +27,7 @@ SDL_bool frames_init(struct frames *frames) { SDL_DestroyMutex(frames->mutex); goto error_2; } + frames->stopped = SDL_FALSE; #endif // there is initially no rendering frame, so consider it has already been @@ -60,24 +61,23 @@ static void frames_swap(struct frames *frames) { SDL_bool frames_offer_decoded_frame(struct frames *frames) { mutex_lock(frames->mutex); - SDL_bool previous_frame_consumed; #ifndef SKIP_FRAMES // if SKIP_FRAMES is disabled, then the decoder must wait for the current // frame to be consumed - while (!frames->rendering_frame_consumed) { + while (!frames->rendering_frame_consumed && !frames->stopped) { cond_wait(frames->rendering_frame_consumed_cond, frames->mutex); } - // by definition, we are not skipping the frames - previous_frame_consumed = SDL_TRUE; #else - previous_frame_consumed = frames->rendering_frame_consumed; - if (!previous_frame_consumed) { + if (!frames->rendering_frame_consumed) { SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Skip frame"); } #endif frames_swap(frames); + + SDL_bool previous_frame_consumed = frames->rendering_frame_consumed; frames->rendering_frame_consumed = SDL_FALSE; + mutex_unlock(frames->mutex); return previous_frame_consumed; } @@ -92,3 +92,15 @@ const AVFrame *frames_consume_rendered_frame(struct frames *frames) { #endif return frames->rendering_frame; } + +void frames_stop(struct frames *frames) { +#ifdef SKIP_FRAMES + (void) frames; // unused +#else + mutex_lock(frames->mutex); + frames->stopped = SDL_TRUE; + mutex_unlock(frames->mutex); + // wake up blocking wait + cond_signal(frames->rendering_frame_consumed_cond); +#endif +} diff --git a/app/src/frames.h b/app/src/frames.h index f96675b2..86142525 100644 --- a/app/src/frames.h +++ b/app/src/frames.h @@ -14,6 +14,7 @@ struct frames { AVFrame *rendering_frame; SDL_mutex *mutex; #ifndef SKIP_FRAMES + SDL_bool stopped; SDL_cond *rendering_frame_consumed_cond; #endif SDL_bool rendering_frame_consumed; @@ -33,4 +34,7 @@ SDL_bool frames_offer_decoded_frame(struct frames *frames); // unlocking frames->mutex const AVFrame *frames_consume_rendered_frame(struct frames *frames); +// wake up and avoid any blocking call +void frames_stop(struct frames *frames); + #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 51974f3e..8784b8d3 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -180,6 +180,7 @@ finally_stop_and_join_controller: finally_destroy_controller: controller_destroy(&controller); finally_stop_decoder: + decoder_stop(&decoder); // kill the server before decoder_join() to wake up the decoder server_stop(&server, serial); decoder_join(&decoder);