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_shadow {
struct m_config *root; struct m_config *root;
pthread_mutex_t lock; 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 // -- protected by lock
struct m_config_data *data; // protected shadow copy of the option data struct m_config_data *data; // protected shadow copy of the option data
struct m_config_cache **listeners; struct m_config_cache **listeners;
@ -81,6 +88,7 @@ struct m_config_group {
// and copies for m_config_cache. // and copies for m_config_cache.
struct m_config_data { struct m_config_data {
struct m_config *root; // root config (with up-to-date 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[] int group_index; // start index into m_config.groups[]
struct m_group_data *gdata; // user struct allocation (our copy of data) struct m_group_data *gdata; // user struct allocation (our copy of data)
int num_gdata; // (group_index+num_gdata = end index) 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) struct m_config_data *copy)
{ {
assert(group_index == data->group_index + data->num_gdata); assert(group_index == data->group_index + data->num_gdata);
assert(group_index < data->root->num_groups); assert(group_index < data->shadow->num_groups);
struct m_config_group *group = &data->root->groups[group_index]; struct m_config_group *group = &data->shadow->groups[group_index];
const struct m_sub_options *opts = group->group; const struct m_sub_options *opts = group->group;
MP_TARRAY_GROW(data, data->gdata, data->num_gdata); 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++) { for (int i = 0; i < data->num_gdata; i++) {
struct m_group_data *gdata = &data->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++) { for (int n = group->co_index; n < group->co_end_index; n++) {
struct m_config_option *co = &data->root->opts[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, int group_index,
struct m_config_data *copy) 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); struct m_config_data *data = talloc_zero(ta_parent, struct m_config_data);
talloc_set_destructor(data, free_option_data); talloc_set_destructor(data, free_option_data);
data->root = root; data->root = root;
data->shadow = shadow;
data->group_index = group_index; 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); assert(root_group->group_count > 0);
for (int n = group_index; n < group_index + root_group->group_count; n++) 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; struct m_config *config = p;
m_config_restore_backups(config); m_config_restore_backups(config);
talloc_free(config->data);
if (config->shadow) { if (config->shadow) {
// must all have been unregistered // must all have been unregistered
assert(config->shadow->num_listeners == 0); assert(config->shadow->num_listeners == 0);
talloc_free(config->shadow->data);
pthread_mutex_destroy(&config->shadow->lock); pthread_mutex_destroy(&config->shadow->lock);
talloc_free(config->shadow); talloc_free(config->shadow);
} }
talloc_free(config->data);
} }
struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log, 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); talloc_set_destructor(config, config_destroy);
*config = (struct m_config){.log = log,}; *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); struct m_sub_options *subopts = talloc_ptrtype(config, subopts);
*subopts = (struct m_sub_options){ *subopts = (struct m_sub_options){
.opts = 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->data = allocate_option_data(config, config, 0, NULL);
config->optstruct = config->data->gdata[0].udata; 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++) { for (int n = 0; n < config->num_opts; n++) {
struct m_config_option *co = &config->opts[n]; struct m_config_option *co = &config->opts[n];
struct m_group_data *gdata = m_config_gdata(config->data, co->group_index); 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) const struct m_option *cfg)
{ {
struct m_config_shadow *shadow = global->config; struct m_config_shadow *shadow = global->config;
struct m_config *root = shadow->root;
for (int n = 0; n < root->num_groups; n++) { for (int n = 0; n < shadow->num_groups; n++) {
if (root->groups[n].group->opts == cfg) if (shadow->groups[n].group->opts == cfg)
return &root->groups[n]; return &shadow->groups[n];
} }
return NULL; 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, int parent_group_index, int parent_ptr,
const struct m_sub_options *subopts) const struct m_sub_options *subopts)
{ {
// Can't be used multiple times. struct m_config_shadow *shadow = config->shadow;
for (int n = 0; n < config->num_groups; n++)
assert(config->groups[n].group != subopts); // 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. // You can only use UPDATE_ flags here.
assert(!(subopts->change_flags & ~(unsigned)UPDATE_OPTS_MASK)); 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++; int group_index = shadow->num_groups++;
MP_TARRAY_GROW(config, config->groups, group_index); MP_TARRAY_GROW(shadow, shadow->groups, group_index);
config->groups[group_index] = (struct m_config_group){ shadow->groups[group_index] = (struct m_config_group){
.group = subopts, .group = subopts,
.parent_group = parent_group_index, .parent_group = parent_group_index,
.parent_ptr = parent_ptr, .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); 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 // Initialize sub-structs. These have to come after, because co_index and
// co_end_index must strictly be for a single struct only. // 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, 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) if (co->opt->defval)
return 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) if (co->opt->offset >= 0 && subopt->defaults)
return (char *)subopt->defaults + co->opt->offset; 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) void m_config_create_shadow(struct m_config *config)
{ {
assert(config->global); assert(config->global);
assert(!config->shadow && !config->global->config); assert(!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);
config->global->config = config->shadow; 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) const struct m_sub_options *group)
{ {
struct m_config_shadow *shadow = global->config; struct m_config_shadow *shadow = global->config;
struct m_config *root = shadow->root;
int group_index = -1; 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. // 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; group_index = n;
break; break;
} }
@ -1271,7 +1287,8 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent,
cache->shadow = shadow; cache->shadow = shadow;
pthread_mutex_lock(&shadow->lock); 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); pthread_mutex_unlock(&shadow->lock);
cache->opts = cache->data->gdata[0].udata; 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) static bool update_options(struct m_config_data *dst, struct m_config_data *src)
{ {
assert(dst->root == src->root); assert(dst->root == src->root);
assert(dst->shadow == src->shadow);
bool res = false; bool res = false;
dst->ts = src->ts; 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_s = MPMAX(dst->group_index, src->group_index);
int group_e = MPMIN(dst->group_index + dst->num_gdata, int group_e = MPMIN(dst->group_index + dst->num_gdata,
src->group_index + src->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++) { 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 *gsrc = m_config_gdata(src, n);
struct m_group_data *gdst = m_config_gdata(dst, n); struct m_group_data *gdst = m_config_gdata(dst, n);
assert(gsrc && gdst); 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 changed = co->opt->flags & UPDATE_OPTS_MASK;
int group_index = co->group_index; int group_index = co->group_index;
while (group_index >= 0) { 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; changed |= g->group->change_flags;
group_index = g->parent_group; group_index = g->parent_group;
} }

View File

@ -87,13 +87,6 @@ typedef struct m_config {
void *optstruct; // struct mpopts or other 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. // Private. Non-NULL if data was allocated. m_config_option.data uses it.
struct m_config_data *data; struct m_config_data *data;