summaryrefslogtreecommitdiffstats
path: root/player/client.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/client.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/client.c')
-rw-r--r--player/client.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/player/client.c b/player/client.c
index b6282a1134..31339f47a3 100644
--- a/player/client.c
+++ b/player/client.c
@@ -1063,9 +1063,14 @@ static int run_client_command(mpv_handle *ctx, struct mp_cmd *cmd, mpv_node *res
lock_core(ctx);
if (async) {
- run_command(ctx->mpctx, req.cmd, NULL, NULL);
+ run_command(ctx->mpctx, cmd, NULL, NULL, NULL);
} else {
- run_command(ctx->mpctx, req.cmd, cmd_complete, &req);
+ struct mp_abort_entry *abort = NULL;
+ if (cmd->def->can_abort) {
+ abort = talloc_zero(NULL, struct mp_abort_entry);
+ abort->client = ctx;
+ }
+ run_command(ctx->mpctx, cmd, abort, cmd_complete, &req);
}
unlock_core(ctx);
@@ -1129,9 +1134,17 @@ static void async_cmd_fn(void *data)
ta_xset_parent(cmd, NULL);
req->cmd = NULL;
+ struct mp_abort_entry *abort = NULL;
+ if (cmd->def->can_abort) {
+ abort = talloc_zero(NULL, struct mp_abort_entry);
+ abort->client = req->reply_ctx;
+ abort->client_work_type = MPV_EVENT_COMMAND_REPLY;
+ abort->client_work_id = req->userdata;
+ }
+
// This will synchronously or asynchronously call cmd_complete (depending
// on the command).
- run_command(req->mpctx, cmd, async_cmd_complete, req);
+ run_command(req->mpctx, cmd, abort, async_cmd_complete, req);
}
static int run_async_cmd(mpv_handle *ctx, uint64_t ud, struct mp_cmd *cmd)
@@ -1163,6 +1176,23 @@ int mpv_command_node_async(mpv_handle *ctx, uint64_t ud, mpv_node *args)
return run_async_cmd(ctx, ud, mp_input_parse_cmd_node(ctx->log, args));
}
+void mpv_abort_async_command(mpv_handle *ctx, uint64_t reply_userdata)
+{
+ struct MPContext *mpctx = ctx->mpctx;
+
+ pthread_mutex_lock(&mpctx->abort_lock);
+ for (int n = 0; n < mpctx->num_abort_list; n++) {
+ struct mp_abort_entry *abort = mpctx->abort_list[n];
+ if (abort->client == ctx &&
+ abort->client_work_type == MPV_EVENT_COMMAND_REPLY &&
+ abort->client_work_id == reply_userdata)
+ {
+ mp_abort_trigger_locked(mpctx, abort);
+ }
+ }
+ pthread_mutex_unlock(&mpctx->abort_lock);
+}
+
static int translate_property_error(int errc)
{
switch (errc) {