summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-03-26 23:58:09 +0100
committerwm4 <wm4@nowhere>2020-03-26 23:59:44 +0100
commit1a720377203f7cee2ab949c5aa2bc9e0a2a7e0f2 (patch)
treebc2028b3823c06d59091797536c32623ebc555a8 /player
parent9bda301eb4d8aa75d435f24146c3a66ab74cafea (diff)
downloadmpv-1a720377203f7cee2ab949c5aa2bc9e0a2a7e0f2.tar.bz2
mpv-1a720377203f7cee2ab949c5aa2bc9e0a2a7e0f2.tar.xz
scripting: remove race condition when toggling internal scripts
Scripts such as the OSC can be loaded and unloaded at runtime by toggling the option that enables them. (It even works, although normally it's only used to control initial loading.) Unloading was racy because it used the client name; fix this. The load-script change is an accidental feature. And probably useless.
Diffstat (limited to 'player')
-rw-r--r--player/client.c8
-rw-r--r--player/client.h1
-rw-r--r--player/command.c8
-rw-r--r--player/core.h4
-rw-r--r--player/scripting.c37
5 files changed, 27 insertions, 31 deletions
diff --git a/player/client.c b/player/client.c
index a72cb0125f..d2a94cc0c9 100644
--- a/player/client.c
+++ b/player/client.c
@@ -254,14 +254,6 @@ static struct mpv_handle *find_client(struct mp_client_api *clients,
return NULL;
}
-bool mp_client_exists(struct MPContext *mpctx, const char *client_name)
-{
- pthread_mutex_lock(&mpctx->clients->lock);
- bool r = find_client(mpctx->clients, client_name);
- pthread_mutex_unlock(&mpctx->clients->lock);
- return r;
-}
-
bool mp_client_id_exists(struct MPContext *mpctx, int64_t id)
{
pthread_mutex_lock(&mpctx->clients->lock);
diff --git a/player/client.h b/player/client.h
index 47af084cc5..ddc568e975 100644
--- a/player/client.h
+++ b/player/client.h
@@ -23,7 +23,6 @@ void mp_shutdown_clients(struct MPContext *mpctx);
bool mp_is_shutting_down(struct MPContext *mpctx);
bool mp_clients_all_initialized(struct MPContext *mpctx);
-bool mp_client_exists(struct MPContext *mpctx, const char *client_name);
bool mp_client_id_exists(struct MPContext *mpctx, int64_t id);
void mp_client_broadcast_event(struct MPContext *mpctx, int event, void *data);
int mp_client_send_event(struct MPContext *mpctx, const char *client_name,
diff --git a/player/command.c b/player/command.c
index 3098e1d9bf..822a54c4a7 100644
--- a/player/command.c
+++ b/player/command.c
@@ -5538,8 +5538,14 @@ static void cmd_load_script(void *p)
struct MPContext *mpctx = cmd->mpctx;
char *script = cmd->args[0].v.s;
- if (mp_load_user_script(mpctx, script) < 0)
+ int64_t id = mp_load_user_script(mpctx, script);
+ if (id > 0) {
+ struct mpv_node *res = &cmd->result;
+ node_init(res, MPV_FORMAT_NODE_MAP, NULL);
+ node_map_add_int64(res, "client_id", id);
+ } else {
cmd->success = false;
+ }
}
static void cache_dump_poll(struct MPContext *mpctx)
diff --git a/player/core.h b/player/core.h
index 5161b07799..9472dfefd3 100644
--- a/player/core.h
+++ b/player/core.h
@@ -444,6 +444,8 @@ typedef struct MPContext {
struct mp_ipc_ctx *ipc_ctx;
+ int64_t builtin_script_ids[4];
+
pthread_mutex_t abort_lock;
// --- The following fields are protected by abort_lock
@@ -632,7 +634,7 @@ struct mp_scripting {
};
bool mp_load_scripts(struct MPContext *mpctx);
void mp_load_builtin_scripts(struct MPContext *mpctx);
-int mp_load_user_script(struct MPContext *mpctx, const char *fname);
+int64_t mp_load_user_script(struct MPContext *mpctx, const char *fname);
// sub.c
void reset_subtitle_state(struct MPContext *mpctx);
diff --git a/player/scripting.c b/player/scripting.c
index 81623cb518..840ff3e64a 100644
--- a/player/scripting.c
+++ b/player/scripting.c
@@ -105,7 +105,7 @@ static void *script_thread(void *p)
return NULL;
}
-static int mp_load_script(struct MPContext *mpctx, const char *fname)
+static int64_t mp_load_script(struct MPContext *mpctx, const char *fname)
{
char *ext = mp_splitext(fname, NULL);
if (ext && strcasecmp(ext, "disable") == 0)
@@ -183,6 +183,7 @@ static int mp_load_script(struct MPContext *mpctx, const char *fname)
mp_client_set_weak(arg->client);
arg->log = mp_client_get_log(arg->client);
+ int64_t id = mpv_client_id(arg->client);
MP_DBG(arg, "Loading %s %s...\n", backend->name, fname);
@@ -197,13 +198,13 @@ static int mp_load_script(struct MPContext *mpctx, const char *fname)
}
}
- return 0;
+ return id;
}
-int mp_load_user_script(struct MPContext *mpctx, const char *fname)
+int64_t mp_load_user_script(struct MPContext *mpctx, const char *fname)
{
char *path = mp_get_user_path(NULL, mpctx->global, fname);
- int ret = mp_load_script(mpctx, path);
+ int64_t ret = mp_load_script(mpctx, path);
talloc_free(path);
return ret;
}
@@ -238,33 +239,29 @@ static char **list_script_files(void *talloc_ctx, char *path)
return files;
}
-static void load_builtin_script(struct MPContext *mpctx, bool enable,
+static void load_builtin_script(struct MPContext *mpctx, int slot, bool enable,
const char *fname)
{
- void *tmp = talloc_new(NULL);
- // (The name doesn't have to match if there were conflicts with other
- // scripts, so this is on best-effort basis.)
- char *name = script_name_from_filename(tmp, fname);
- if (enable != mp_client_exists(mpctx, name)) {
+ assert(slot < MP_ARRAY_SIZE(mpctx->builtin_script_ids));
+ int64_t *pid = &mpctx->builtin_script_ids[slot];
+ if (*pid > 0 && !mp_client_id_exists(mpctx, *pid))
+ *pid = 0; // died
+ if ((*pid > 0) != enable) {
if (enable) {
- mp_load_script(mpctx, fname);
+ *pid = mp_load_script(mpctx, fname);
} else {
- // Try to unload it by sending a shutdown event. This can be
- // unreliable, because user scripts could have clashing names, or
- // disabling and then quickly re-enabling a builtin script might
- // detect the still-terminating script as loaded.
+ char *name = mp_tprintf(22, "@%"PRIi64, *pid);
mp_client_send_event(mpctx, name, 0, MPV_EVENT_SHUTDOWN, NULL);
}
}
- talloc_free(tmp);
}
void mp_load_builtin_scripts(struct MPContext *mpctx)
{
- load_builtin_script(mpctx, mpctx->opts->lua_load_osc, "@osc.lua");
- load_builtin_script(mpctx, mpctx->opts->lua_load_ytdl, "@ytdl_hook.lua");
- load_builtin_script(mpctx, mpctx->opts->lua_load_stats, "@stats.lua");
- load_builtin_script(mpctx, mpctx->opts->lua_load_console, "@console.lua");
+ load_builtin_script(mpctx, 0, mpctx->opts->lua_load_osc, "@osc.lua");
+ load_builtin_script(mpctx, 1, mpctx->opts->lua_load_ytdl, "@ytdl_hook.lua");
+ load_builtin_script(mpctx, 2, mpctx->opts->lua_load_stats, "@stats.lua");
+ load_builtin_script(mpctx, 3, mpctx->opts->lua_load_console, "@console.lua");
}
bool mp_load_scripts(struct MPContext *mpctx)