summaryrefslogtreecommitdiffstats
path: root/player/command.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/command.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/command.c')
-rw-r--r--player/command.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/player/command.c b/player/command.c
index f2d7eedd5f..cd623c03f4 100644
--- a/player/command.c
+++ b/player/command.c
@@ -4865,7 +4865,7 @@ static void continue_cmd_list(struct cmd_list_ctx *list)
if (sub->flags & MP_ASYNC_CMD) {
// We run it "detached" (fire & forget)
- run_command(list->mpctx, sub, NULL, NULL);
+ run_command(list->mpctx, sub, NULL, NULL, NULL);
} else {
// Run the next command once this one completes.
@@ -4873,7 +4873,7 @@ static void continue_cmd_list(struct cmd_list_ctx *list)
list->current_valid = true;
list->current = pthread_self();
- run_command(list->mpctx, sub, on_cmd_list_sub_completion, list);
+ run_command(list->mpctx, sub, NULL, on_cmd_list_sub_completion, list);
list->current_valid = false;
@@ -4920,8 +4920,9 @@ void mp_cmd_ctx_complete(struct mp_cmd_ctx *cmd)
mpv_free_node_contents(&cmd->result);
if (cmd->on_completion)
cmd->on_completion(cmd);
+ if (cmd->abort)
+ mp_abort_remove(cmd->mpctx, cmd->abort);
mpv_free_node_contents(&cmd->result);
- talloc_free(cmd->cmd);
talloc_free(cmd);
}
@@ -4949,27 +4950,40 @@ static void run_command_on_worker_thread(void *p)
// function returns (the caller is supposed to be able to handle both cases). In
// both cases, the callback will be called while the core is locked (i.e. you
// can access the core freely).
+// If abort is non-NULL, then the caller creates the abort object. It must have
+// been allocated with talloc. run_command() will register/unregister/destroy
+// it. Must not be set if cmd->def->can_abort==false.
// on_completion_priv is copied to mp_cmd_ctx.on_completion_priv and can be
// accessed from the completion callback.
// The completion callback is invoked exactly once. If it's NULL, it's ignored.
// Ownership of cmd goes to the caller.
void run_command(struct MPContext *mpctx, struct mp_cmd *cmd,
+ struct mp_abort_entry *abort,
void (*on_completion)(struct mp_cmd_ctx *cmd),
void *on_completion_priv)
{
struct mp_cmd_ctx *ctx = talloc(NULL, struct mp_cmd_ctx);
*ctx = (struct mp_cmd_ctx){
.mpctx = mpctx,
- .cmd = cmd,
+ .cmd = talloc_steal(ctx, cmd),
.args = cmd->args,
.num_args = cmd->nargs,
.priv = cmd->def->priv,
+ .abort = talloc_steal(ctx, abort),
.success = true,
.completed = true,
.on_completion = on_completion,
.on_completion_priv = on_completion_priv,
};
+ if (!ctx->abort && cmd->def->can_abort)
+ ctx->abort = talloc_zero(ctx, struct mp_abort_entry);
+
+ assert(cmd->def->can_abort == !!ctx->abort);
+
+ if (ctx->abort)
+ mp_abort_add(mpctx, ctx->abort);
+
struct MPOpts *opts = mpctx->opts;
ctx->on_osd = cmd->flags & MP_ON_OSD_FLAGS;
bool auto_osd = ctx->on_osd == MP_ON_OSD_AUTO;