Fix: PictureFlow crashes

- After appending albums, when memory had been borrowed
from the buflib buffer by shifting memory up using  buflib_buffer_out()
in create_track_index(), memory was later not shifted down using
buflib_buffer_in() (the latter was only called after displaying the track list).

- The picture loading thread was able to allocate memory from the
buflib pool while the main thread was moving the buffer around.
Slide loading will now be paused before shifting operations, and
continued afterwards.

Change-Id: I1c92b6c931fd14ebb885be4bc275148039b76a9a
This commit is contained in:
Christian Soffke 2021-11-14 22:20:09 +01:00 committed by Solomon Peachy
parent 3f966b2aa4
commit f9ce8720c4

View file

@ -495,6 +495,15 @@ static struct pf_track_t pf_tracks;
void reset_track_list(void); void reset_track_list(void);
static bool thread_is_running; static bool thread_is_running;
static bool wants_to_quit = false;
/*
Prevent picture loading thread from allocating
buflib memory while the main thread may be
performing buffer-shifting operations.
*/
static struct mutex buf_ctx_mutex;
static bool buf_ctx_locked = false;
static int cover_animation_keyframe; static int cover_animation_keyframe;
static int extra_fade; static int extra_fade;
@ -537,6 +546,18 @@ static void draw_progressbar(int step, int count, char *msg);
static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size); static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size);
static void free_all_slide_prio(int prio); static void free_all_slide_prio(int prio);
static inline void buf_ctx_lock(void)
{
rb->mutex_lock(&buf_ctx_mutex);
buf_ctx_locked = true;
}
static inline void buf_ctx_unlock(void)
{
rb->mutex_unlock(&buf_ctx_mutex);
buf_ctx_locked = false;
}
static bool check_database(bool prompt) static bool check_database(bool prompt)
{ {
bool needwarn = true; bool needwarn = true;
@ -1590,6 +1611,7 @@ static int compare_tracks (const void *a_v, const void *b_v)
*/ */
static void create_track_index(const int slide_index) static void create_track_index(const int slide_index)
{ {
buf_ctx_lock();
char temp[MAX_PATH + 1]; char temp[MAX_PATH + 1];
if ( slide_index == pf_tracks.cur_idx ) if ( slide_index == pf_tracks.cur_idx )
return; return;
@ -1735,6 +1757,18 @@ fail:
return; return;
} }
/**
Re-grow the buflib buffer by returning space borrowed
for track list
*/
static inline void free_borrowed_tracks(void)
{
rb->buflib_buffer_in(&buf_ctx, pf_tracks.borrowed);
pf_tracks.borrowed = 0;
pf_tracks.cur_idx = -1;
buf_ctx_unlock();
}
/** /**
Determine filename of the album art for the given slide_index and Determine filename of the album art for the given slide_index and
store the result in buf. store the result in buf.
@ -2371,6 +2405,10 @@ static inline bool load_and_prepare_surface(const int slide_index,
*/ */
bool load_new_slide(void) bool load_new_slide(void)
{ {
buf_ctx_lock();
if (wants_to_quit)
return false;
int i = -1; int i = -1;
if (pf_sldcache.center_idx != -1) if (pf_sldcache.center_idx != -1)
@ -2417,6 +2455,7 @@ bool load_new_slide(void)
pf_sldcache.center_idx = i; pf_sldcache.center_idx = i;
pf_sldcache.left_idx = i; pf_sldcache.left_idx = i;
pf_sldcache.right_idx = i; pf_sldcache.right_idx = i;
buf_ctx_unlock();
return true; return true;
} }
} }
@ -2447,25 +2486,33 @@ bool load_new_slide(void)
if ((prio_l < prio_r || right >= number_of_slides) && left > 0) if ((prio_l < prio_r || right >= number_of_slides) && left > 0)
{ {
if (pf_sldcache.free == -1 && !free_slide_prio(prio_l)) if (pf_sldcache.free == -1 && !free_slide_prio(prio_l))
{
buf_ctx_unlock();
return false; return false;
}
i = lla_pop_head(&pf_sldcache.free); i = lla_pop_head(&pf_sldcache.free);
if (load_and_prepare_surface(left - 1, i, prio_l)) if (load_and_prepare_surface(left - 1, i, prio_l))
{ {
lla_insert_before(&pf_sldcache.used, i, pf_sldcache.left_idx); lla_insert_before(&pf_sldcache.used, i, pf_sldcache.left_idx);
pf_sldcache.left_idx = i; pf_sldcache.left_idx = i;
buf_ctx_unlock();
return true; return true;
} }
} else if(right < number_of_slides - 1) } else if(right < number_of_slides - 1)
{ {
if (pf_sldcache.free == -1 && !free_slide_prio(prio_r)) if (pf_sldcache.free == -1 && !free_slide_prio(prio_r))
{
buf_ctx_unlock();
return false; return false;
}
i = lla_pop_head(&pf_sldcache.free); i = lla_pop_head(&pf_sldcache.free);
if (load_and_prepare_surface(right + 1, i, prio_r)) if (load_and_prepare_surface(right + 1, i, prio_r))
{ {
lla_insert_after(i, pf_sldcache.right_idx); lla_insert_after(i, pf_sldcache.right_idx);
pf_sldcache.right_idx = i; pf_sldcache.right_idx = i;
buf_ctx_unlock();
return true; return true;
} }
} }
@ -2480,6 +2527,7 @@ insert_first_slide:
pf_sldcache.left_idx = i; pf_sldcache.left_idx = i;
pf_sldcache.right_idx = i; pf_sldcache.right_idx = i;
pf_sldcache.used = i; pf_sldcache.used = i;
buf_ctx_unlock();
return true; return true;
} }
} }
@ -2488,6 +2536,7 @@ fail_and_refree:
{ {
lla_insert_tail(&pf_sldcache.free, i); lla_insert_tail(&pf_sldcache.free, i);
} }
buf_ctx_unlock();
return false; return false;
} }
@ -3004,6 +3053,10 @@ static void update_scroll_animation(void)
*/ */
static void cleanup(void) static void cleanup(void)
{ {
wants_to_quit = true;
if (buf_ctx_locked)
buf_ctx_unlock();
#ifdef HAVE_ADJUSTABLE_CPU_FREQ #ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false); rb->cpu_boost(false);
#endif #endif
@ -3552,6 +3605,8 @@ static int pictureflow_main(void)
#endif #endif
} }
rb->mutex_init(&buf_ctx_mutex);
init_scroll_lines(); init_scroll_lines();
init_reflect_table(); init_reflect_table();
@ -3759,10 +3814,8 @@ static int pictureflow_main(void)
case PF_BACK: case PF_BACK:
if ( pf_state == pf_show_tracks ) if ( pf_state == pf_show_tracks )
{ {
rb->buflib_buffer_in(&buf_ctx, pf_tracks.borrowed);
pf_tracks.borrowed = 0;
pf_tracks.cur_idx = -1;
pf_state = pf_cover_out; pf_state = pf_cover_out;
free_borrowed_tracks();
} }
if (pf_state == pf_idle || pf_state == pf_scrolling) if (pf_state == pf_idle || pf_state == pf_scrolling)
return PLUGIN_OK; return PLUGIN_OK;
@ -3803,6 +3856,7 @@ static int pictureflow_main(void)
create_track_index(center_slide.slide_index); create_track_index(center_slide.slide_index);
reset_track_list(); reset_track_list();
start_playback(true); start_playback(true);
free_borrowed_tracks();
rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST));
} }
else if( pf_state == pf_show_tracks ) { else if( pf_state == pf_show_tracks ) {