summaryrefslogtreecommitdiffstats
path: root/player/loadfile.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-05-12 18:46:37 +0200
committerwm4 <wm4@nowhere>2018-05-24 19:56:34 +0200
commite4fb23ed7de874bb2d05824d7edb84cfd1b21101 (patch)
treeff56d6949cdead5795607c86882ce44aca0b7da7 /player/loadfile.c
parentce1f5e78c2b10e24c78d7ee65d7196093709b8ce (diff)
downloadmpv-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.c51
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++) {