1
mirror of https://github.com/mpv-player/mpv synced 2024-11-14 22:48:35 +01:00

m_config: move group list to internal context

This is good because a private thing is not so public anymore, and it's
also preparation for further changes.

Some tricky memory management issues: m_config_data (i.e. config->data)
now depends on m_config_shadow, instead of m_config. In particular,
free_option_data() accesses the m_config_shadow.groups array. Obviously
it must be freed before m_config_shadow.
This commit is contained in:
wm4 2019-07-13 00:38:28 +02:00
parent 98627d3a32
commit 059262c746
2 changed files with 53 additions and 42 deletions

View File

@ -57,6 +57,13 @@ static const union m_option_value default_value;
struct m_config_shadow {
struct m_config *root;
pthread_mutex_t lock;
// -- immutable after init
// List of m_sub_options instances.
// Index 0 is the top-level and is always present.
// Immutable after init.
// Invariant: a parent is always at a lower index than any of its children.
struct m_config_group *groups;
int num_groups;
// -- protected by lock
struct m_config_data *data; // protected shadow copy of the option data
struct m_config_cache **listeners;
@ -81,6 +88,7 @@ struct m_config_group {
// and copies for m_config_cache.
struct m_config_data {
struct m_config *root; // root config (with up-to-date data)
struct m_config_shadow *shadow; // option definitions etc.
int group_index; // start index into m_config.groups[]
struct m_group_data *gdata; // user struct allocation (our copy of data)
int num_gdata; // (group_index+num_gdata = end index)
@ -197,8 +205,8 @@ static void alloc_group(struct m_config_data *data, int group_index,
struct m_config_data *copy)
{
assert(group_index == data->group_index + data->num_gdata);
assert(group_index < data->root->num_groups);
struct m_config_group *group = &data->root->groups[group_index];
assert(group_index < data->shadow->num_groups);
struct m_config_group *group = &data->shadow->groups[group_index];
const struct m_sub_options *opts = group->group;
MP_TARRAY_GROW(data, data->gdata, data->num_gdata);
@ -248,7 +256,8 @@ static void free_option_data(void *p)
for (int i = 0; i < data->num_gdata; i++) {
struct m_group_data *gdata = &data->gdata[i];
struct m_config_group *group = &data->root->groups[data->group_index + i];
struct m_config_group *group =
&data->shadow->groups[data->group_index + i];
for (int n = group->co_index; n < group->co_end_index; n++) {
struct m_config_option *co = &data->root->opts[n];
@ -268,14 +277,17 @@ static struct m_config_data *allocate_option_data(void *ta_parent,
int group_index,
struct m_config_data *copy)
{
assert(group_index >= 0 && group_index < root->num_groups);
struct m_config_shadow *shadow = root->shadow;
assert(group_index >= 0 && group_index < shadow->num_groups);
struct m_config_data *data = talloc_zero(ta_parent, struct m_config_data);
talloc_set_destructor(data, free_option_data);
data->root = root;
data->shadow = shadow;
data->group_index = group_index;
struct m_config_group *root_group = &root->groups[group_index];
struct m_config_group *root_group = &shadow->groups[group_index];
assert(root_group->group_count > 0);
for (int n = group_index; n < group_index + root_group->group_count; n++)
@ -292,14 +304,15 @@ static void config_destroy(void *p)
struct m_config *config = p;
m_config_restore_backups(config);
talloc_free(config->data);
if (config->shadow) {
// must all have been unregistered
assert(config->shadow->num_listeners == 0);
talloc_free(config->shadow->data);
pthread_mutex_destroy(&config->shadow->lock);
talloc_free(config->shadow);
}
talloc_free(config->data);
}
struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
@ -310,6 +323,10 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
talloc_set_destructor(config, config_destroy);
*config = (struct m_config){.log = log,};
config->shadow = talloc_zero(NULL, struct m_config_shadow);
pthread_mutex_init(&config->shadow->lock, NULL);
config->shadow->root = config;
struct m_sub_options *subopts = talloc_ptrtype(config, subopts);
*subopts = (struct m_sub_options){
.opts = options,
@ -324,6 +341,9 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
config->data = allocate_option_data(config, config, 0, NULL);
config->optstruct = config->data->gdata[0].udata;
config->shadow->data =
allocate_option_data(config->shadow, config, 0, config->data);
for (int n = 0; n < config->num_opts; n++) {
struct m_config_option *co = &config->opts[n];
struct m_group_data *gdata = m_config_gdata(config->data, co->group_index);
@ -359,11 +379,10 @@ static const struct m_config_group *find_group(struct mpv_global *global,
const struct m_option *cfg)
{
struct m_config_shadow *shadow = global->config;
struct m_config *root = shadow->root;
for (int n = 0; n < root->num_groups; n++) {
if (root->groups[n].group->opts == cfg)
return &root->groups[n];
for (int n = 0; n < shadow->num_groups; n++) {
if (shadow->groups[n].group->opts == cfg)
return &shadow->groups[n];
}
return NULL;
@ -509,18 +528,20 @@ static void add_sub_group(struct m_config *config, const char *name_prefix,
int parent_group_index, int parent_ptr,
const struct m_sub_options *subopts)
{
// Can't be used multiple times.
for (int n = 0; n < config->num_groups; n++)
assert(config->groups[n].group != subopts);
struct m_config_shadow *shadow = config->shadow;
// Can't be used multiple times.
for (int n = 0; n < shadow->num_groups; n++)
assert(shadow->groups[n].group != subopts);
// You can only use UPDATE_ flags here.
assert(!(subopts->change_flags & ~(unsigned)UPDATE_OPTS_MASK));
assert(parent_group_index >= -1 && parent_group_index < config->num_groups);
assert(parent_group_index >= -1 && parent_group_index < shadow->num_groups);
int group_index = config->num_groups++;
MP_TARRAY_GROW(config, config->groups, group_index);
config->groups[group_index] = (struct m_config_group){
int group_index = shadow->num_groups++;
MP_TARRAY_GROW(shadow, shadow->groups, group_index);
shadow->groups[group_index] = (struct m_config_group){
.group = subopts,
.parent_group = parent_group_index,
.parent_ptr = parent_ptr,
@ -547,7 +568,7 @@ static void add_sub_group(struct m_config *config, const char *name_prefix,
MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
}
config->groups[group_index].co_end_index = config->num_opts;
shadow->groups[group_index].co_end_index = config->num_opts;
// Initialize sub-structs. These have to come after, because co_index and
// co_end_index must strictly be for a single struct only.
@ -571,7 +592,7 @@ static void add_sub_group(struct m_config *config, const char *name_prefix,
}
}
config->groups[group_index].group_count = config->num_groups - group_index;
shadow->groups[group_index].group_count = shadow->num_groups - group_index;
}
struct m_config_option *m_config_get_co_raw(const struct m_config *config,
@ -665,7 +686,9 @@ const void *m_config_get_co_default(const struct m_config *config,
if (co->opt->defval)
return co->opt->defval;
const struct m_sub_options *subopt = config->groups[co->group_index].group;
const struct m_sub_options *subopt =
config->shadow->groups[co->group_index].group;
if (co->opt->offset >= 0 && subopt->defaults)
return (char *)subopt->defaults + co->opt->offset;
@ -1227,13 +1250,7 @@ struct mpv_node m_config_get_profiles(struct m_config *config)
void m_config_create_shadow(struct m_config *config)
{
assert(config->global);
assert(!config->shadow && !config->global->config);
config->shadow = talloc_zero(NULL, struct m_config_shadow);
config->shadow->data =
allocate_option_data(config->shadow, config, 0, config->data);
config->shadow->root = config;
pthread_mutex_init(&config->shadow->lock, NULL);
assert(!config->global->config);
config->global->config = config->shadow;
}
@ -1253,12 +1270,11 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent,
const struct m_sub_options *group)
{
struct m_config_shadow *shadow = global->config;
struct m_config *root = shadow->root;
int group_index = -1;
for (int n = 0; n < root->num_groups; n++) {
for (int n = 0; n < shadow->num_groups; n++) {
// group==NULL is special cased to root group.
if (root->groups[n].group == group || (!group && !n)) {
if (shadow->groups[n].group == group || (!group && !n)) {
group_index = n;
break;
}
@ -1271,7 +1287,8 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent,
cache->shadow = shadow;
pthread_mutex_lock(&shadow->lock);
cache->data = allocate_option_data(cache, root, group_index, shadow->data);
cache->data =
allocate_option_data(cache, shadow->root, group_index, shadow->data);
pthread_mutex_unlock(&shadow->lock);
cache->opts = cache->data->gdata[0].udata;
@ -1282,6 +1299,7 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent,
static bool update_options(struct m_config_data *dst, struct m_config_data *src)
{
assert(dst->root == src->root);
assert(dst->shadow == src->shadow);
bool res = false;
dst->ts = src->ts;
@ -1290,9 +1308,9 @@ static bool update_options(struct m_config_data *dst, struct m_config_data *src)
int group_s = MPMAX(dst->group_index, src->group_index);
int group_e = MPMIN(dst->group_index + dst->num_gdata,
src->group_index + src->num_gdata);
assert(group_s >= 0 && group_e <= dst->root->num_groups);
assert(group_s >= 0 && group_e <= dst->shadow->num_groups);
for (int n = group_s; n < group_e; n++) {
struct m_config_group *g = &dst->root->groups[n];
struct m_config_group *g = &dst->shadow->groups[n];
struct m_group_data *gsrc = m_config_gdata(src, n);
struct m_group_data *gdst = m_config_gdata(dst, n);
assert(gsrc && gdst);
@ -1359,7 +1377,7 @@ void m_config_notify_change_co(struct m_config *config,
int changed = co->opt->flags & UPDATE_OPTS_MASK;
int group_index = co->group_index;
while (group_index >= 0) {
struct m_config_group *g = &config->groups[group_index];
struct m_config_group *g = &shadow->groups[group_index];
changed |= g->group->change_flags;
group_index = g->parent_group;
}

View File

@ -87,13 +87,6 @@ typedef struct m_config {
void *optstruct; // struct mpopts or other
// Private. List of m_sub_options instances.
// Index 0 is the top-level and is always present.
// Immutable after init.
// Invariant: a parent is always at a lower index than any of its children.
struct m_config_group *groups;
int num_groups;
// Private. Non-NULL if data was allocated. m_config_option.data uses it.
struct m_config_data *data;