From e4fb23ed7de874bb2d05824d7edb84cfd1b21101 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 12 May 2018 18:46:37 +0200 Subject: command: add a way to abort asynchronous commands Many asynchronous commands are potentially long running operations, such as loading something from network or running a foreign process. Obviously it shouldn't just be possible for them to freeze the player if they don't terminate as expected. Also, there will be situations where you want to explicitly stop some of those operations explicitly. So add an infrastructure for this. Commands have to support this explicitly. The next commit uses this to actually add support to a command. --- player/loadfile.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'player/loadfile.c') diff --git a/player/loadfile.c b/player/loadfile.c index e1864f3fd5..6f28d2ee38 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -67,11 +67,62 @@ void mp_abort_playback_async(struct MPContext *mpctx) mp_cancel_trigger(mpctx->playback_abort); pthread_mutex_lock(&mpctx->abort_lock); + if (mpctx->demuxer_cancel) mp_cancel_trigger(mpctx->demuxer_cancel); + + for (int n = 0; n < mpctx->num_abort_list; n++) { + struct mp_abort_entry *abort = mpctx->abort_list[n]; + if (abort->coupled_to_playback) + mp_abort_trigger_locked(mpctx, abort); + } + + pthread_mutex_unlock(&mpctx->abort_lock); +} + +// Add it to the global list, and allocate required data structures. +void mp_abort_add(struct MPContext *mpctx, struct mp_abort_entry *abort) +{ + pthread_mutex_lock(&mpctx->abort_lock); + assert(!abort->cancel); + abort->cancel = mp_cancel_new(NULL); + MP_TARRAY_APPEND(NULL, mpctx->abort_list, mpctx->num_abort_list, abort); + mp_abort_recheck_locked(mpctx, abort); pthread_mutex_unlock(&mpctx->abort_lock); } +// Remove Add it to the global list, and free/clear required data structures. +// Does not deallocate the abort value itself. +void mp_abort_remove(struct MPContext *mpctx, struct mp_abort_entry *abort) +{ + pthread_mutex_lock(&mpctx->abort_lock); + for (int n = 0; n < mpctx->num_abort_list; n++) { + if (mpctx->abort_list[n] == abort) { + MP_TARRAY_REMOVE_AT(mpctx->abort_list, mpctx->num_abort_list, n); + TA_FREEP(&abort->cancel); + abort = NULL; // it's not free'd, just clear for the assert below + break; + } + } + assert(!abort); // should have been in the list + pthread_mutex_unlock(&mpctx->abort_lock); +} + +// Verify whether the abort needs to be signaled after changing certain fields +// in abort. +void mp_abort_recheck_locked(struct MPContext *mpctx, + struct mp_abort_entry *abort) +{ + if (abort->coupled_to_playback && mp_cancel_test(mpctx->playback_abort)) + mp_abort_trigger_locked(mpctx, abort); +} + +void mp_abort_trigger_locked(struct MPContext *mpctx, + struct mp_abort_entry *abort) +{ + mp_cancel_trigger(abort->cancel); +} + static void uninit_demuxer(struct MPContext *mpctx) { for (int r = 0; r < NUM_PTRACKS; r++) { -- cgit v1.2.3