summaryrefslogtreecommitdiffstats
path: root/player/client.c
diff options
context:
space:
mode:
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)