summaryrefslogtreecommitdiffstats
path: root/options/m_config.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-11-28 21:59:39 +0100
committerwm4 <wm4@nowhere>2019-11-29 12:14:43 +0100
commitf73881fa10e3ba1e43d3a8b984379533c0c40284 (patch)
tree7bb16052e4d332586d958d09a12cd419395c1bd7 /options/m_config.c
parent591494b271f17c4bfae0cfb860ae12bdad98a2ca (diff)
downloadmpv-f73881fa10e3ba1e43d3a8b984379533c0c40284.tar.bz2
mpv-f73881fa10e3ba1e43d3a8b984379533c0c40284.tar.xz
m_config: allow writing options through m_config_cache
This will allow any other threads to write to the global option data in a safe way. The typical example for this is the fullscreen option, which needs to be written by VO (or even some other thing running completely separate from the main thread). We have a complicated and annoying contraption which gets the value updated on the main thread, and this function will help get rid of it. As of this commit, this doesn't really work yet, because he main thread uses its own weird copy of the option data.
Diffstat (limited to 'options/m_config.c')
-rw-r--r--options/m_config.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/options/m_config.c b/options/m_config.c
index c6e0d02fc8..001c238464 100644
--- a/options/m_config.c
+++ b/options/m_config.c
@@ -1421,6 +1421,66 @@ bool m_config_cache_get_next_changed(struct m_config_cache *cache, void **opt)
return !!*opt;
}
+static void find_opt(struct m_config_shadow *shadow, struct m_config_data *data,
+ void *ptr, int *group_idx, int *opt_idx)
+{
+ *group_idx = -1;
+ *opt_idx = -1;
+
+ for (int n = data->group_index; n < data->group_index + data->num_gdata; n++)
+ {
+ struct m_group_data *gd = m_config_gdata(data, n);
+ struct m_config_group *g = &shadow->groups[n];
+ const struct m_option *opts = g->group->opts;
+
+ for (int i = 0; opts && opts[i].name; i++) {
+ const struct m_option *opt = &opts[i];
+
+ if (opt->offset >= 0 && opt->type->size &&
+ ptr == gd->udata + opt->offset)
+ {
+ *group_idx = n;
+ *opt_idx = i;
+ return;
+ }
+ }
+ }
+}
+
+void m_config_cache_write_opt(struct m_config_cache *cache, void *ptr)
+{
+ struct config_cache *in = cache->internal;
+ struct m_config_shadow *shadow = in->shadow;
+
+ int group_idx = -1;
+ int opt_idx = -1;
+ find_opt(shadow, in->data, ptr, &group_idx, &opt_idx);
+
+ // ptr was not in cache->opts, or no option declaration matching it.
+ assert(group_idx >= 0);
+
+ struct m_config_group *g = &shadow->groups[group_idx];
+ const struct m_option *opt = &g->group->opts[opt_idx];
+
+ pthread_mutex_lock(&shadow->lock);
+
+ struct m_group_data *gdst = m_config_gdata(in->data, group_idx);
+ struct m_group_data *gsrc = m_config_gdata(in->src, group_idx);
+ assert(gdst && gsrc);
+
+ m_option_copy(opt, gsrc->udata + opt->offset, ptr);
+
+ gsrc->ts = atomic_fetch_add(&shadow->ts, 1) + 1;
+
+ for (int n = 0; n < shadow->num_listeners; n++) {
+ struct config_cache *listener = shadow->listeners[n];
+ if (listener->wakeup_cb && m_config_gdata(listener->data, group_idx))
+ listener->wakeup_cb(listener->wakeup_cb_ctx);
+ }
+
+ pthread_mutex_unlock(&shadow->lock);
+}
+
void m_config_notify_change_co(struct m_config *config,
struct m_config_option *co)
{