summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-03-13 00:42:48 +0100
committerwm4 <wm4@nowhere>2020-03-13 16:50:27 +0100
commit28de668173b0c142d4d227eddbc15d7e25b3efbe (patch)
tree761d05f3e2e3684566701a5d6a2fdae32e1334cb
parenteb381cbd4b38dd496ee0be609f1a66c360a76448 (diff)
downloadmpv-28de668173b0c142d4d227eddbc15d7e25b3efbe.tar.bz2
mpv-28de668173b0c142d4d227eddbc15d7e25b3efbe.tar.xz
options: more pushing code around
Try to remove m_config implementation details from m_config_frontend. Not sure if I like it. Seems to be ~100 lines of awkward code more, and not much is gained from it. Also it took way too long to do it, and there might be bugs.
-rw-r--r--options/m_config_core.c288
-rw-r--r--options/m_config_core.h55
-rw-r--r--options/m_config_frontend.c51
-rw-r--r--options/m_config_frontend.h2
4 files changed, 245 insertions, 151 deletions
diff --git a/options/m_config_core.c b/options/m_config_core.c
index 0b7d40ea6e..f82b886670 100644
--- a/options/m_config_core.c
+++ b/options/m_config_core.c
@@ -33,9 +33,6 @@
#include "misc/dispatch.h"
#include "osdep/atomic.h"
-// Maximum possibly option name length (as it appears to the user).
-#define MAX_OPT_NAME_LEN 80
-
// For use with m_config_cache.
struct m_config_shadow {
pthread_mutex_t lock;
@@ -57,6 +54,7 @@ struct m_config_shadow {
// Represents a sub-struct (OPT_SUBSTRUCT()).
struct m_config_group {
const struct m_sub_options *group;
+ int opt_count; // cached opt. count; group->opts[opt_count].name==NULL
int group_count; // 1 + number of all sub groups owned by this (so
// m_config_shadow.groups[idx..idx+group_count] is used
// by the entire tree of sub groups included by this
@@ -84,6 +82,7 @@ struct config_cache {
struct m_config_data *data; // public data
struct m_config_data *src; // global data (currently ==shadow->data)
struct m_config_shadow *shadow; // global metadata
+ int group_start, group_end; // derived from data->group_index etc.
uint64_t ts; // timestamp of this data copy
bool in_list; // part of m_config_shadow->listeners[]
int upd_group; // for "incremental" change notification
@@ -106,6 +105,7 @@ struct m_group_data {
uint64_t ts; // timestamp of the data copy
};
+static const union m_option_value default_value = {0};
static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefix,
int parent_group_index, int parent_ptr,
@@ -140,71 +140,150 @@ static const char *concat_name_buf(char *buf, size_t buf_size,
// a, b, or a talloc'ed string under ta_parent.
static const char *concat_name(void *ta_parent, const char *a, const char *b)
{
- char buf[MAX_OPT_NAME_LEN];
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
const char *r = concat_name_buf(buf, sizeof(buf), a, b);
return r == buf ? talloc_strdup(ta_parent, r) : r;
}
-struct opt_iterate_state {
- // User can read these fields.
- int group_index;
- int opt_index;
- const struct m_option *opt;
- const char *full_name; // may point to name_buf
+static bool iter_next(struct m_config_shadow *shadow, int group_start,
+ int group_end, int32_t *p_id)
+{
+ int32_t id = *p_id;
+ int group_index = id == -1 ? group_start : id >> 16;
+ int opt_index = id == -1 ? -1 : id & 0xFFFF;
+
+ assert(group_index >= group_start && group_index <= group_end);
- // Internal.
- int group_index_end;
- char name_buf[MAX_OPT_NAME_LEN];
- struct m_config_shadow *shadow;
-};
+ while (1) {
+ if (group_index >= group_end)
+ return false;
+
+ struct m_config_group *g = &shadow->groups[group_index];
+ const struct m_option *opts = g->group->opts;
+
+ assert(opt_index >= -1 && opt_index < g->opt_count);
+
+ opt_index += 1;
+
+ if (!opts || !opts[opt_index].name) {
+ group_index += 1;
+ opt_index = -1;
+ continue;
+ }
-// Start iterating all options and sub-options in the given group.
-static void opt_iterate_init(struct opt_iterate_state *iter,
- struct m_config_shadow *shadow, int group_index)
+ if (opts[opt_index].type == &m_option_type_subconfig)
+ continue;
+
+ *p_id = (group_index << 16) | opt_index;
+ return true;
+ }
+}
+
+bool m_config_shadow_get_next_opt(struct m_config_shadow *shadow, int32_t *p_id)
+{
+ return iter_next(shadow, 0, shadow->num_groups, p_id);
+}
+
+bool m_config_cache_get_next_opt(struct m_config_cache *cache, int32_t *p_id)
{
+ return iter_next(cache->shadow, cache->internal->group_start,
+ cache->internal->group_end, p_id);
+}
+
+static void get_opt_from_id(struct m_config_shadow *shadow, int32_t id,
+ int *out_group_index, int *out_opt_index)
+{
+ int group_index = id >> 16;
+ int opt_index = id & 0xFFFF;
+
assert(group_index >= 0 && group_index < shadow->num_groups);
- iter->group_index = group_index;
- iter->group_index_end = group_index + shadow->groups[group_index].group_count;
- iter->opt_index = -1;
- iter->shadow = shadow;
+ assert(opt_index >= 0 && opt_index < shadow->groups[group_index].opt_count);
+
+ *out_group_index = group_index;
+ *out_opt_index = opt_index;
}
-// Get the first or next option. Returns false if end reached. If this returns
-// true, most fields in *iter are valid.
-// This does not return pseudo-option entries (like m_option_type_subconfig).
-static bool opt_iterate_next(struct opt_iterate_state *iter)
+const struct m_option *m_config_shadow_get_opt(struct m_config_shadow *shadow,
+ int32_t id)
{
- if (iter->group_index < 0)
- return false;
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+ return &shadow->groups[group_index].group->opts[opt_index];
+}
- while (1) {
- if (iter->group_index >= iter->group_index_end) {
- iter->group_index = -1;
- return false;
- }
+const char *m_config_shadow_get_opt_name(struct m_config_shadow *shadow,
+ int32_t id, char *buf, size_t buf_size)
+{
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+
+ struct m_config_group *g = &shadow->groups[group_index];
+ return concat_name_buf(buf, buf_size, g->prefix,
+ g->group->opts[opt_index].name);
+}
- iter->opt_index += 1;
+const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
+ int32_t id)
+{
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
- struct m_config_group *g = &iter->shadow->groups[iter->group_index];
- const struct m_option *opts = g->group->opts;
+ const struct m_sub_options *subopt = shadow->groups[group_index].group;
+ const struct m_option *opt = &subopt->opts[opt_index];
- if (!opts || !opts[iter->opt_index].name) {
- iter->group_index += 1;
- iter->opt_index = -1;
- continue;
- }
+ if (opt->offset < 0)
+ return NULL;
- iter->opt = &opts[iter->opt_index];
+ if (opt->defval)
+ return opt->defval;
- if (iter->opt->type == &m_option_type_subconfig)
- continue;
+ if (subopt->defaults)
+ return (char *)subopt->defaults + opt->offset;
- iter->full_name = concat_name_buf(iter->name_buf, sizeof(iter->name_buf),
- g->prefix, iter->opt->name);
- return true;
+ return &default_value;
+}
+
+void *m_config_cache_get_opt_data(struct m_config_cache *cache, int32_t id)
+{
+ int group_index, opt_index;
+ get_opt_from_id(cache->shadow, id, &group_index, &opt_index);
+
+ assert(group_index >= cache->internal->group_start &&
+ group_index < cache->internal->group_end);
+
+ struct m_group_data *gd = m_config_gdata(cache->internal->data, group_index);
+ const struct m_option *opt =
+ &cache->shadow->groups[group_index].group->opts[opt_index];
+
+ return gd && opt->offset >= 0 ? gd->udata + opt->offset : NULL;
+}
+
+static uint64_t get_opt_change_mask(struct m_config_shadow *shadow, int group_index,
+ int group_root, const struct m_option *opt)
+{
+ uint64_t changed = opt->flags & UPDATE_OPTS_MASK;
+ while (group_index != group_root) {
+ struct m_config_group *g = &shadow->groups[group_index];
+ changed |= g->group->change_flags;
+ group_index = g->parent_group;
}
- assert(0);
+ return changed;
+}
+
+uint64_t m_config_cache_get_option_change_mask(struct m_config_cache *cache,
+ int32_t id)
+{
+ struct m_config_shadow *shadow = cache->shadow;
+ int group_index, opt_index;
+ get_opt_from_id(shadow, id, &group_index, &opt_index);
+
+ assert(group_index >= cache->internal->group_start &&
+ group_index < cache->internal->group_end);
+
+ return get_opt_change_mask(cache->shadow, group_index,
+ cache->internal->data->group_index,
+ &shadow->groups[group_index].group->opts[opt_index]);
}
// The memcpys are supposed to work around the strict aliasing violation,
@@ -359,54 +438,6 @@ struct m_config_shadow *m_config_shadow_new(const struct m_sub_options *root)
return shadow;
}
-#include "m_config_frontend.h"
-
-static void config_destroy(void *p)
-{
- struct m_config *config = p;
- config->option_change_callback = NULL;
- m_config_restore_backups(config);
-
- talloc_free(config->cache);
- talloc_free(config->shadow);
-}
-
-struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
- const struct m_sub_options *root)
-{
- struct m_config *config = talloc(talloc_ctx, struct m_config);
- talloc_set_destructor(config, config_destroy);
- *config = (struct m_config){.log = log,};
-
- config->shadow = m_config_shadow_new(root);
-
- if (root->size) {
- config->cache = m_config_cache_from_shadow(config, config->shadow, root);
- config->optstruct = config->cache->opts;
- }
-
- struct opt_iterate_state it;
- opt_iterate_init(&it, config->shadow, 0);
- while (opt_iterate_next(&it)) {
- struct m_config_option co = {
- .name = talloc_strdup(config, it.full_name),
- .opt = it.opt,
- .group_index = it.group_index,
- };
-
- struct m_group_data *gdata = config->cache
- ? m_config_gdata(config->cache->internal->data, it.group_index)
- : NULL;
-
- if (gdata && co.opt->offset >= 0)
- co.data = gdata->udata + co.opt->offset;
-
- MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
- }
-
- return config;
-}
-
static void init_obj_settings_list(struct m_config_shadow *shadow,
int parent_group_index,
const struct m_obj_list *list)
@@ -480,6 +511,8 @@ static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefi
const struct m_obj_list *objlist = opt->priv;
init_obj_settings_list(shadow, group_index, objlist);
}
+
+ shadow->groups[group_index].opt_count = i + 1;
}
if (subopts->get_sub_options) {
@@ -495,19 +528,6 @@ static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefi
shadow->groups[group_index].group_count = shadow->num_groups - group_index;
}
-uint64_t m_config_shadow_get_option_change_mask(struct m_config_shadow *shadow,
- int group_index, int group_root,
- const struct m_option *opt)
-{
- uint64_t changed = opt->flags & UPDATE_OPTS_MASK;
- while (group_index != group_root) {
- struct m_config_group *g = &shadow->groups[group_index];
- changed |= g->group->change_flags;
- group_index = g->parent_group;
- }
- return changed;
-}
-
static void cache_destroy(void *p)
{
struct m_config_cache *cache = p;
@@ -542,6 +562,7 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
struct m_config_cache *cache = &alloc->a;
talloc_set_destructor(cache, cache_destroy);
cache->internal = &alloc->b;
+ cache->shadow = shadow;
struct config_cache *in = cache->internal;
in->shadow = shadow;
@@ -553,6 +574,10 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
cache->opts = in->data->gdata[0].udata;
+ in->group_start = in->data->group_index;
+ in->group_end = in->group_start + in->data->num_gdata;
+ assert(shadow->groups[in->group_start].group_count == in->data->num_gdata);
+
in->upd_group = -1;
return cache;
@@ -592,8 +617,7 @@ static void update_next_option(struct m_config_cache *cache, void **p_opt)
void *ddst = gdst->udata + opt->offset;
if (!m_option_equal(opt, ddst, dsrc)) {
- uint64_t ch =
- m_config_shadow_get_option_change_mask(dst->shadow,
+ uint64_t ch = get_opt_change_mask(dst->shadow,
in->upd_group, dst->group_index, opt);
if (cache->debug) {
@@ -831,19 +855,26 @@ void mp_read_option_raw(struct mpv_global *global, const char *name,
{
struct m_config_shadow *shadow = global->config;
- struct opt_iterate_state it;
- opt_iterate_init(&it, shadow, 0);
- while (opt_iterate_next(&it)) {
- if (strcmp(name, it.full_name) == 0) {
- struct m_group_data *gdata =
- m_config_gdata(shadow->data, it.group_index);
+ int32_t optid = -1;
+ while (m_config_shadow_get_next_opt(shadow, &optid)) {
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
+ const char *opt_name =
+ m_config_shadow_get_opt_name(shadow, optid, buf, sizeof(buf));
+
+ if (strcmp(name, opt_name) == 0) {
+ const struct m_option *opt = m_config_shadow_get_opt(shadow, optid);
+
+ int group_index, opt_index;
+ get_opt_from_id(shadow, optid, &group_index, &opt_index);
+
+ struct m_group_data *gdata = m_config_gdata(shadow->data, group_index);
assert(gdata);
- assert(it.opt->offset >= 0);
- assert(it.opt->type == type);
+ assert(opt->offset >= 0);
+ assert(opt->type == type);
- memset(dst, 0, it.opt->type->size);
- m_option_copy(it.opt, dst, gdata->udata + it.opt->offset);
+ memset(dst, 0, opt->type->size);
+ m_option_copy(opt, dst, gdata->udata + opt->offset);
return;
}
}
@@ -877,18 +908,3 @@ void *m_config_group_from_desc(void *ta_parent, struct mp_log *log,
return d;
}
}
-
-const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
- int group_index,
- const struct m_option *opt)
-{
- if (opt->defval)
- return opt->defval;
-
- const struct m_sub_options *subopt = shadow->groups[group_index].group;
-
- if (opt->offset >= 0 && subopt->defaults)
- return (char *)subopt->defaults + opt->offset;
-
- return NULL;
-}
diff --git a/options/m_config_core.h b/options/m_config_core.h
index f3fc716aa9..c4902be9d1 100644
--- a/options/m_config_core.h
+++ b/options/m_config_core.h
@@ -25,8 +25,8 @@
struct mp_dispatch_queue;
struct m_sub_options;
struct m_option_type;
+struct m_option;
struct mpv_global;
-struct m_config_shadow;
// This can be used to create and synchronize per-thread option structs,
// which then can be read without synchronization. No concurrent access to
@@ -44,10 +44,16 @@ struct m_config_cache {
// with one of the update functions (like m_config_cache_update()).
struct mp_log *debug;
+ // Global instance of option data. Read only.
+ struct m_config_shadow *shadow;
+
// Do not access.
struct config_cache *internal;
};
+// Maximum possibly option name buffer length (as it appears to the user).
+#define M_CONFIG_MAX_OPT_NAME_LEN 80
+
// Create a mirror copy from the global options.
// Keep in mind that a m_config_cache object is not thread-safe; it merely
// provides thread-safe access to the global options. All API functions for
@@ -152,15 +158,44 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
struct m_config_shadow *shadow,
const struct m_sub_options *group);
-// Bad function.
-struct m_option;
-uint64_t m_config_shadow_get_option_change_mask(struct m_config_shadow *shadow,
- int group_index, int group_root,
- const struct m_option *opt);
-
-// Bad function.
+// Iterate over all registered global options. *p_id must be set to -1 when this
+// is called for the first time. Each time this call returns true, *p_id is set
+// to a new valid option ID. p_id must not be changed for the next call. If
+// false is returned, iteration ends.
+bool m_config_shadow_get_next_opt(struct m_config_shadow *shadow, int32_t *p_id);
+
+// Similar to m_config_shadow_get_next_opt(), but return only options that are
+// covered by the m_config_cache.
+bool m_config_cache_get_next_opt(struct m_config_cache *cache, int32_t *p_id);
+
+// Return the m_option that was used to declare this option.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
+const struct m_option *m_config_shadow_get_opt(struct m_config_shadow *shadow,
+ int32_t id);
+
+// Return the full (global) option name. buf must be supplied, but may not
+// always be used. It should have the size M_CONFIG_MAX_OPT_NAME_LEN.
+// The returned point points either to buf or a static string.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
+const char *m_config_shadow_get_opt_name(struct m_config_shadow *shadow,
+ int32_t id, char *buf, size_t buf_size);
+
+// Pointer to default value, using m_option.type. NULL if option without data.
+// id must be a valid option ID as returned by m_config_shadow_get_next_opt() or
+// m_config_cache_get_next_opt().
const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
- int group_index,
- const struct m_option *opt);
+ int32_t id);
+
+// Return the pointer to the allocated option data (the same pointers that are
+// returned by m_config_cache_get_next_changed()). NULL if option without data.
+// id must be a valid option ID as returned by m_config_cache_get_next_opt().
+void *m_config_cache_get_opt_data(struct m_config_cache *cache, int32_t id);
+
+// Return or-ed UPDATE_OPTS_MASK part of the option and containing sub-options.
+// id must be a valid option ID as returned by m_config_cache_get_next_opt().
+uint64_t m_config_cache_get_option_change_mask(struct m_config_cache *cache,
+ int32_t id);
#endif /* MPLAYER_M_CONFIG_H */
diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c
index 6eeea084c4..ab93203645 100644
--- a/options/m_config_frontend.c
+++ b/options/m_config_frontend.c
@@ -309,8 +309,7 @@ struct m_config_option *m_config_get_co_index(struct m_config *config, int index
const void *m_config_get_co_default(const struct m_config *config,
struct m_config_option *co)
{
- return m_config_shadow_get_opt_default(config->shadow, co->group_index,
- co->opt);
+ return m_config_shadow_get_opt_default(config->shadow, co->opt_id);
}
const char *m_config_get_positional_option(const struct m_config *config, int p)
@@ -464,6 +463,51 @@ void m_config_set_update_dispatch_queue(struct m_config *config,
async_change_cb, config);
}
+static void config_destroy(void *p)
+{
+ struct m_config *config = p;
+ config->option_change_callback = NULL;
+ m_config_restore_backups(config);
+
+ talloc_free(config->cache);
+ talloc_free(config->shadow);
+}
+
+struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
+ const struct m_sub_options *root)
+{
+ struct m_config *config = talloc(talloc_ctx, struct m_config);
+ talloc_set_destructor(config, config_destroy);
+ *config = (struct m_config){.log = log,};
+
+ config->shadow = m_config_shadow_new(root);
+
+ if (root->size) {
+ config->cache = m_config_cache_from_shadow(config, config->shadow, root);
+ config->optstruct = config->cache->opts;
+ }
+
+ int32_t optid = -1;
+ while (m_config_shadow_get_next_opt(config->shadow, &optid)) {
+ char buf[M_CONFIG_MAX_OPT_NAME_LEN];
+ const char *opt_name =
+ m_config_shadow_get_opt_name(config->shadow, optid, buf, sizeof(buf));
+
+ struct m_config_option co = {
+ .name = talloc_strdup(config, opt_name),
+ .opt = m_config_shadow_get_opt(config->shadow, optid),
+ .opt_id = optid,
+ };
+
+ if (config->cache)
+ co.data = m_config_cache_get_opt_data(config->cache, optid);
+
+ MP_TARRAY_APPEND(config, config->opts, config->num_opts, co);
+ }
+
+ return config;
+}
+
// Normally m_config_cache will not send notifications when _we_ change our
// own stuff. For whatever funny reasons, we need that, though.
static void force_self_notify_change_opt(struct m_config *config,
@@ -471,8 +515,7 @@ static void force_self_notify_change_opt(struct m_config *config,
bool self_notification)
{
int changed =
- m_config_shadow_get_option_change_mask(config->shadow, co->group_index,
- 0, co->opt);
+ m_config_cache_get_option_change_mask(config->cache, co->opt_id);
if (config->option_change_callback) {
config->option_change_callback(config->option_change_callback_ctx, co,
diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h
index 82d2ded2d6..19fbcadf25 100644
--- a/options/m_config_frontend.h
+++ b/options/m_config_frontend.h
@@ -50,7 +50,7 @@ struct m_config_option {
bool is_set_from_config : 1; // Set by a config file
bool is_set_locally : 1; // Has a backup entry
bool warning_was_printed : 1;
- int16_t group_index; // Index into m_config.groups
+ int32_t opt_id; // For some m_config APIs
const char *name; // Full name (ie option-subopt)
const struct m_option *opt; // Option description
void *data; // Raw value of the option