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:
parent
98627d3a32
commit
059262c746
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user