Skip to content

Commit

Permalink
client API: add mpv_wait_async_requests()
Browse files Browse the repository at this point in the history
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 mpv-player#1542.
  • Loading branch information
wm4 authored and olifre committed Feb 28, 2015
1 parent ba8364a commit c47650b
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 9 deletions.
1 change: 1 addition & 0 deletions DOCS/client-api-changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 15 additions & 1 deletion libmpv/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions libmpv/mpv.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
20 changes: 12 additions & 8 deletions player/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit c47650b

Please sign in to comment.