diff options
Diffstat (limited to 'options/m_config.c')
-rw-r--r-- | options/m_config.c | 144 |
1 files changed, 84 insertions, 60 deletions
diff --git a/options/m_config.c b/options/m_config.c index 52a9b2f6d8..a28ae4438b 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -142,6 +142,9 @@ struct m_opt_backup { void *backup; }; +static struct m_config_cache *m_config_cache_alloc_internal(void *ta_parent, + struct m_config_shadow *shadow, + const struct m_sub_options *group); static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefix, int parent_group_index, int parent_ptr, const struct m_sub_options *subopts); @@ -446,7 +449,7 @@ static void config_destroy(void *p) struct m_config *config = p; m_config_restore_backups(config); - talloc_free(config->data); + talloc_free(config->cache); talloc_free(config->shadow); } @@ -460,9 +463,9 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log, config->shadow = m_config_shadow_new(root); if (root->size) { - config->data = allocate_option_data(config, config->shadow, 0, - config->shadow->data); - config->optstruct = config->data->gdata[0].udata; + config->cache = + m_config_cache_alloc_internal(config, config->shadow, root); + config->optstruct = config->cache->opts; } struct opt_iterate_state it; @@ -475,8 +478,9 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log, .is_hidden = !!it.opt->deprecation_message, }; - struct m_group_data *gdata = - config->data ? m_config_gdata(config->data, it.group_index) : NULL; + 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; @@ -939,6 +943,67 @@ static int m_config_handle_special_options(struct m_config *config, return M_OPT_UNKNOWN; } +// This notification happens when anyone other than m_config->cache (i.e. not +// through m_config_set_option_raw() or related) changes any options. +static void async_change_cb(void *p) +{ + struct m_config *config = p; + + void *ptr; + while (m_config_cache_get_next_changed(config->cache, &ptr)) { + // Regrettable linear search, might degenerate to quadratic. + for (int n = 0; n < config->num_opts; n++) { + struct m_config_option *co = &config->opts[n]; + if (co->data == ptr) { + if (config->option_change_callback) { + config->option_change_callback( + config->option_change_callback_ctx, co, + config->cache->change_flags, false); + } + break; + } + } + config->cache->change_flags = 0; + } +} + +void m_config_set_update_dispatch_queue(struct m_config *config, + struct mp_dispatch_queue *dispatch) +{ + m_config_cache_set_dispatch_change_cb(config->cache, dispatch, + async_change_cb, 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, + struct m_config_option *co, + bool self_notification) +{ + int changed = + get_option_change_mask(config->shadow, co->group_index, 0, co->opt); + + if (config->option_change_callback) { + config->option_change_callback(config->option_change_callback_ctx, co, + changed, self_notification); + } +} + +void m_config_notify_change_opt_ptr(struct m_config *config, void *ptr) +{ + for (int n = 0; n < config->num_opts; n++) { + struct m_config_option *co = &config->opts[n]; + if (co->data == ptr) { + if (m_config_cache_write_opt(config->cache, co->data)) + force_self_notify_change_opt(config, co, true); + return; + } + } + // ptr doesn't point to any config->optstruct field declared in the + // option list? + assert(false); +} + int m_config_set_option_raw(struct m_config *config, struct m_config_option *co, void *data, int flags) @@ -959,10 +1024,11 @@ int m_config_set_option_raw(struct m_config *config, if (!co->data) return flags & M_SETOPT_FROM_CMDLINE ? 0 : M_OPT_UNKNOWN; - m_option_copy(co->opt, co->data, data); - m_config_mark_co_flags(co, flags); - m_config_notify_change_co(config, co); + + m_option_copy(co->opt, co->data, data); + if (m_config_cache_write_opt(config->cache, co->data)) + force_self_notify_change_opt(config, co, false); return 0; } @@ -1356,11 +1422,10 @@ static void cache_destroy(void *p) m_config_cache_set_dispatch_change_cb(cache, NULL, NULL, NULL); } -struct m_config_cache *m_config_cache_alloc(void *ta_parent, - struct mpv_global *global, +static struct m_config_cache *m_config_cache_alloc_internal(void *ta_parent, + struct m_config_shadow *shadow, const struct m_sub_options *group) { - struct m_config_shadow *shadow = global->config; int group_index = -1; for (int n = 0; n < shadow->num_groups; n++) { @@ -1397,6 +1462,13 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent, return cache; } +struct m_config_cache *m_config_cache_alloc(void *ta_parent, + struct mpv_global *global, + const struct m_sub_options *group) +{ + return m_config_cache_alloc_internal(ta_parent, global->config, group); +} + static void update_next_option(struct m_config_cache *cache, void **p_opt) { struct config_cache *in = cache->internal; @@ -1577,54 +1649,6 @@ bool m_config_cache_write_opt(struct m_config_cache *cache, void *ptr) return changed; } -void m_config_notify_change_co(struct m_config *config, - struct m_config_option *co) -{ - struct m_config_shadow *shadow = config->shadow; - assert(co->data); - - if (shadow) { - pthread_mutex_lock(&shadow->lock); - - struct m_config_data *data = shadow->data; - struct m_group_data *gdata = m_config_gdata(data, co->group_index); - assert(gdata); - - gdata->ts = atomic_fetch_add(&shadow->ts, 1) + 1; - - m_option_copy(co->opt, gdata->udata + co->opt->offset, co->data); - - for (int n = 0; n < shadow->num_listeners; n++) { - struct config_cache *cache = shadow->listeners[n]; - if (cache->wakeup_cb && m_config_gdata(cache->data, co->group_index)) - cache->wakeup_cb(cache->wakeup_cb_ctx); - } - - pthread_mutex_unlock(&shadow->lock); - } - - int changed = get_option_change_mask(shadow, co->group_index, 0, co->opt); - - if (config->option_change_callback) { - config->option_change_callback(config->option_change_callback_ctx, co, - changed); - } -} - -void m_config_notify_change_opt_ptr(struct m_config *config, void *ptr) -{ - for (int n = 0; n < config->num_opts; n++) { - struct m_config_option *co = &config->opts[n]; - if (co->data == ptr) { - m_config_notify_change_co(config, co); - return; - } - } - // ptr doesn't point to any config->optstruct field declared in the - // option list? - assert(false); -} - void m_config_cache_set_wakeup_cb(struct m_config_cache *cache, void (*cb)(void *ctx), void *cb_ctx) { |