From ef827af06cbf334a497fb0de8c9b75188549d03e Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 2 Feb 2015 17:24:33 +0100 Subject: [PATCH] client API: add mpv_wait_async_requests() This does what it's documented to do. The implementation reuses the code in mpv_detach_destroy(). Due to the way async requests currently work, just sending a synchronous dummy request (like a "ignore" command) would be enough to ensure synchronization, but this code will continue to work even if this changes. The line "ctx->event_mask = 0;" is removed, but it shouldn't be needed. (If a client is somehow very slow to terminate, this could silence an annoying queue overflow message, but all in all it does nothing.) Calling mpv_wait_async_requests() and mpv_wait_event() concurrently is in theory allowed, so change pthread_cond_signal() to pthread_cond_broadcast() to avoid missed wakeups. As requested in issue #1542. --- DOCS/client-api-changes.rst | 1 + libmpv/client.h | 16 +++++++++++++++- libmpv/mpv.def | 1 + player/client.c | 20 ++++++++++++-------- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst index 8fa325a870..626474779b 100644 --- a/DOCS/client-api-changes.rst +++ b/DOCS/client-api-changes.rst @@ -25,6 +25,7 @@ API changes :: + 1.14 - add mpv_wait_async_requests() 1.13 - add MPV_EVENT_QUEUE_OVERFLOW 1.12 - add class Handle to qthelper.hpp - improve opengl_cb.h API uninitialization behavior, and fix the qml diff --git a/libmpv/client.h b/libmpv/client.h index 7208912ee0..500f03cd94 100644 --- a/libmpv/client.h +++ b/libmpv/client.h @@ -167,7 +167,7 @@ extern "C" { * relational operators (<, >, <=, >=). */ #define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL) -#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 13) +#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 14) /** * Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with. @@ -1478,6 +1478,20 @@ void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d); */ int mpv_get_wakeup_pipe(mpv_handle *ctx); +/** + * Block until all asynchronous requests are done. This affects functions like + * mpv_command_async(), which return immediately and return their result as + * events. + * + * This is a helper, and somewhat equivalent to calling mpv_wait_event() in a + * loop until all known asynchronous requests have sent their reply as event, + * except that the event queue is not emptied. + * + * In case you called mpv_suspend() before, this will also forcibly reset the + * suspend counter of the given handle. + */ +void mpv_wait_async_requests(mpv_handle *ctx); + typedef enum mpv_sub_api { /** * For using mpv's OpenGL renderer on an external OpenGL context. diff --git a/libmpv/mpv.def b/libmpv/mpv.def index 5176beaa8a..d4d45874fa 100644 --- a/libmpv/mpv.def +++ b/libmpv/mpv.def @@ -38,5 +38,6 @@ mpv_set_wakeup_callback mpv_suspend mpv_terminate_destroy mpv_unobserve_property +mpv_wait_async_requests mpv_wait_event mpv_wakeup \ No newline at end of file diff --git a/player/client.c b/player/client.c index ae4f1f3898..1c24d5522e 100644 --- a/player/client.c +++ b/player/client.c @@ -269,7 +269,7 @@ static void wakeup_client(struct mpv_handle *ctx) pthread_mutex_lock(&ctx->wakeup_lock); if (!ctx->need_wakeup) { ctx->need_wakeup = true; - pthread_cond_signal(&ctx->wakeup); + pthread_cond_broadcast(&ctx->wakeup); if (ctx->wakeup_cb) ctx->wakeup_cb(ctx->wakeup_cb_ctx); if (ctx->wakeup_pipe[0] != -1) @@ -360,21 +360,25 @@ static void unlock_core(mpv_handle *ctx) mp_dispatch_unlock(ctx->mpctx->dispatch); } +void mpv_wait_async_requests(mpv_handle *ctx) +{ + mp_resume_all(ctx); + + pthread_mutex_lock(&ctx->lock); + while (ctx->reserved_events || ctx->properties_updating) + wait_wakeup(ctx, INT64_MAX); + pthread_mutex_unlock(&ctx->lock); +} + void mpv_detach_destroy(mpv_handle *ctx) { if (!ctx) return; - mp_resume_all(ctx); - - pthread_mutex_lock(&ctx->lock); // 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. - ctx->event_mask = 0; - while (ctx->reserved_events || ctx->properties_updating) - wait_wakeup(ctx, INT64_MAX); - pthread_mutex_unlock(&ctx->lock); + mpv_wait_async_requests(ctx); struct mp_client_api *clients = ctx->clients;