mirror of
https://github.com/mpv-player/mpv
synced 2024-12-18 12:55:16 +00:00
client API: fix init/destruction race conditions
mp_new_client() blatantly accessed some mutex-protected state outside of the mutex. The destruction code is in theory OK, but with changes in the following commits it'll be a bit hard to guarantee that it stays this way. Add a simple flag that makes adding new clients impossible, so that having no clients after shutdown_clients() remains guaranteed.
This commit is contained in:
parent
47f3cc7e6b
commit
14c232bdbf
@ -66,7 +66,8 @@ struct mp_client_api {
|
||||
|
||||
struct mpv_handle **clients;
|
||||
int num_clients;
|
||||
uint64_t event_masks; // combined events of all clients, or 0 if unknown
|
||||
uint64_t event_masks; // combined events of all clients, or 0 if unknown
|
||||
bool shutting_down; // do not allow new clients
|
||||
|
||||
struct mp_custom_protocol *custom_protocols;
|
||||
int num_custom_protocols;
|
||||
@ -206,8 +207,17 @@ bool mp_client_exists(struct MPContext *mpctx, const char *client_name)
|
||||
return r;
|
||||
}
|
||||
|
||||
void mp_client_enter_shutdown(struct MPContext *mpctx)
|
||||
{
|
||||
pthread_mutex_lock(&mpctx->clients->lock);
|
||||
mpctx->clients->shutting_down = true;
|
||||
pthread_mutex_unlock(&mpctx->clients->lock);
|
||||
}
|
||||
|
||||
struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name)
|
||||
{
|
||||
pthread_mutex_lock(&clients->lock);
|
||||
|
||||
char nname[MAX_CLIENT_NAME];
|
||||
for (int n = 1; n < 1000; n++) {
|
||||
if (!name)
|
||||
@ -222,10 +232,10 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name
|
||||
nname[0] = '\0';
|
||||
}
|
||||
|
||||
if (!nname[0])
|
||||
if (!nname[0] || clients->shutting_down) {
|
||||
pthread_mutex_unlock(&clients->lock);
|
||||
return NULL;
|
||||
|
||||
pthread_mutex_lock(&clients->lock);
|
||||
}
|
||||
|
||||
int num_events = 1000;
|
||||
|
||||
|
@ -16,6 +16,7 @@ struct mp_log;
|
||||
#define MAX_CLIENT_NAME 64
|
||||
|
||||
void mp_clients_init(struct MPContext *mpctx);
|
||||
void mp_client_enter_shutdown(struct MPContext *mpctx);
|
||||
void mp_clients_destroy(struct MPContext *mpctx);
|
||||
int mp_clients_num(struct MPContext *mpctx);
|
||||
bool mp_clients_all_initialized(struct MPContext *mpctx);
|
||||
|
@ -152,20 +152,20 @@ void mp_print_version(struct mp_log *log, int always)
|
||||
|
||||
static void shutdown_clients(struct MPContext *mpctx)
|
||||
{
|
||||
while (mpctx->clients && mp_clients_num(mpctx)) {
|
||||
mp_client_enter_shutdown(mpctx);
|
||||
while (mp_clients_num(mpctx)) {
|
||||
mp_client_broadcast_event(mpctx, MPV_EVENT_SHUTDOWN, NULL);
|
||||
mp_dispatch_queue_process(mpctx->dispatch, 0);
|
||||
mp_wait_events(mpctx);
|
||||
}
|
||||
}
|
||||
|
||||
void mp_destroy(struct MPContext *mpctx)
|
||||
{
|
||||
shutdown_clients(mpctx);
|
||||
|
||||
mp_uninit_ipc(mpctx->ipc_ctx);
|
||||
mpctx->ipc_ctx = NULL;
|
||||
|
||||
shutdown_clients(mpctx);
|
||||
|
||||
uninit_audio_out(mpctx);
|
||||
uninit_video_out(mpctx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user