summaryrefslogtreecommitdiffstats
path: root/player/client.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-05-13 13:48:47 +0200
committerwm4 <wm4@nowhere>2018-05-24 19:56:34 +0200
commit7428cc51496ca8e56600fdc4034b8f55720f09f9 (patch)
tree4e09e1818b2e60ccf1db3b1ba04cb227275a658f /player/client.c
parent4e05f75261d997cfc48227f5ac1ab8f18101c437 (diff)
downloadmpv-7428cc51496ca8e56600fdc4034b8f55720f09f9.tar.bz2
mpv-7428cc51496ca8e56600fdc4034b8f55720f09f9.tar.xz
client API: kill async commands on termination
This affects async commands started by client API, commands with async capability run in a sync way by client API (think mpv_command_node() with "subprocess"), and detached async work. Since scripts might want to do some cleanup work (that might involve launching processes, don't ask), we don't unconditionally kill everything on exit, but apply an arbitrary timeout of 2 seconds until async commands are aborted.
Diffstat (limited to 'player/client.c')
-rw-r--r--player/client.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/player/client.c b/player/client.c
index 31339f47a3..06fb88c18b 100644
--- a/player/client.c
+++ b/player/client.c
@@ -371,6 +371,30 @@ void mpv_wait_async_requests(mpv_handle *ctx)
pthread_mutex_unlock(&ctx->lock);
}
+// Send abort signal to all matching work items.
+// If type==0, destroy all of the matching ctx.
+// If ctx==0, destroy all.
+static void abort_async(struct MPContext *mpctx, mpv_handle *ctx,
+ int type, uint64_t id)
+{
+ pthread_mutex_lock(&mpctx->abort_lock);
+
+ // Destroy all => ensure any newly appearing work is aborted immediately.
+ if (ctx == NULL)
+ mpctx->abort_all = true;
+
+ for (int n = 0; n < mpctx->num_abort_list; n++) {
+ struct mp_abort_entry *abort = mpctx->abort_list[n];
+ if (!ctx || (abort->client == ctx && (!type ||
+ (abort->client_work_type == type && abort->client_work_id == id))))
+ {
+ mp_abort_trigger_locked(mpctx, abort);
+ }
+ }
+
+ pthread_mutex_unlock(&mpctx->abort_lock);
+}
+
static void get_thread(void *ptr)
{
*(pthread_t *)ptr = pthread_self();
@@ -389,6 +413,8 @@ static void mp_destroy_client(mpv_handle *ctx, bool terminate)
if (terminate)
mpv_command(ctx, (const char*[]){"quit", NULL});
+ abort_async(mpctx, ctx, 0, 0);
+
// reserved_events equals the number of asynchronous requests that weren't
// yet replied. In order to avoid that trying to reply to a removed client
// causes a crash, block until all asynchronous requests were served.
@@ -485,10 +511,14 @@ void mpv_terminate_destroy(mpv_handle *ctx)
}
// Can be called on the core thread only. Idempotent.
+// Also happens to take care of shutting down any async work.
void mp_shutdown_clients(struct MPContext *mpctx)
{
struct mp_client_api *clients = mpctx->clients;
+ // Forcefully abort async work after 2 seconds of waiting.
+ double abort_time = mp_time_sec() + 2;
+
pthread_mutex_lock(&clients->lock);
// Prevent that new clients can appear.
@@ -500,6 +530,16 @@ void mp_shutdown_clients(struct MPContext *mpctx)
{
pthread_mutex_unlock(&clients->lock);
+ double left = abort_time - mp_time_sec();
+ if (left >= 0) {
+ mp_set_timeout(mpctx, left);
+ } else {
+ // Forcefully abort any ongoing async work. This is quite rude and
+ // probably not what everyone wants, so it happens only after a
+ // timeout.
+ abort_async(mpctx, NULL, 0, 0);
+ }
+
mp_client_broadcast_event(mpctx, MPV_EVENT_SHUTDOWN, NULL);
mp_wait_events(mpctx);
@@ -1178,19 +1218,7 @@ int mpv_command_node_async(mpv_handle *ctx, uint64_t ud, mpv_node *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);
+ abort_async(ctx->mpctx, ctx, MPV_EVENT_COMMAND_REPLY, reply_userdata);
}
static int translate_property_error(int errc)