diff options
author | wm4 <wm4@nowhere> | 2018-05-12 18:46:37 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2018-05-24 19:56:34 +0200 |
commit | e4fb23ed7de874bb2d05824d7edb84cfd1b21101 (patch) | |
tree | ff56d6949cdead5795607c86882ce44aca0b7da7 /player/loadfile.c | |
parent | ce1f5e78c2b10e24c78d7ee65d7196093709b8ce (diff) | |
download | mpv-e4fb23ed7de874bb2d05824d7edb84cfd1b21101.tar.bz2 mpv-e4fb23ed7de874bb2d05824d7edb84cfd1b21101.tar.xz |
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.
Diffstat (limited to 'player/loadfile.c')
-rw-r--r-- | player/loadfile.c | 51 |
1 files changed, 51 insertions, 0 deletions
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++) { |