mirror of https://github.com/mpv-player/mpv
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.
This commit is contained in:
parent
591494b271
commit
f73881fa10
|
@ -1421,6 +1421,66 @@ bool m_config_cache_get_next_changed(struct m_config_cache *cache, void **opt)
|
||||||
return !!*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,
|
void m_config_notify_change_co(struct m_config *config,
|
||||||
struct m_config_option *co)
|
struct m_config_option *co)
|
||||||
{
|
{
|
||||||
|
|
|
@ -338,6 +338,20 @@ bool m_config_cache_update(struct m_config_cache *cache);
|
||||||
// returns: *out_ptr!=NULL (true if there was a changed option)
|
// returns: *out_ptr!=NULL (true if there was a changed option)
|
||||||
bool m_config_cache_get_next_changed(struct m_config_cache *cache, void **out_ptr);
|
bool m_config_cache_get_next_changed(struct m_config_cache *cache, void **out_ptr);
|
||||||
|
|
||||||
|
// Copy the option field pointed to by ptr to the global option storage. This
|
||||||
|
// is sort of similar to m_config_set_option_raw(), except doesn't require
|
||||||
|
// access to the main thread. (And you can't pass any flags.)
|
||||||
|
// You write the new value to the option struct, and then call this function
|
||||||
|
// with the pointer to it. You will not get a change notification for it (though
|
||||||
|
// you might still get a redundant wakeup callback).
|
||||||
|
// Changing the option struct and not calling this function before any update
|
||||||
|
// function (like m_config_cache_update()) will leave the value inconsistent,
|
||||||
|
// and will possibly (but not necessarily) overwrite it with the next update
|
||||||
|
// call.
|
||||||
|
// ptr: points to any field in cache->opts that is managed by an option. If
|
||||||
|
// this is not the case, the function crashes for your own good.
|
||||||
|
void m_config_cache_write_opt(struct m_config_cache *cache, void *ptr);
|
||||||
|
|
||||||
// Like m_config_cache_alloc(), but return the struct (m_config_cache->opts)
|
// Like m_config_cache_alloc(), but return the struct (m_config_cache->opts)
|
||||||
// directly, with no way to update the config. Basically this returns a copy
|
// directly, with no way to update the config. Basically this returns a copy
|
||||||
// with a snapshot of the current option values.
|
// with a snapshot of the current option values.
|
||||||
|
|
Loading…
Reference in New Issue