From 059262c7466b4de5349aa0153312b0f44f9ef8ef Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 13 Jul 2019 00:38:28 +0200 Subject: 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. --- options/m_config.c | 88 ++++++++++++++++++++++++++++++++---------------------- options/m_config.h | 7 ----- 2 files changed, 53 insertions(+), 42 deletions(-) (limited to 'options') diff --git a/options/m_config.c b/options/m_config.c index e461602023..92cb2be950 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -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; } diff --git a/options/m_config.h b/options/m_config.h index a640f43eef..207870e12a 100644 --- a/options/m_config.h +++ b/options/m_config.h @@ -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; -- cgit v1.2.3