Partial support for multiplicity in configuration objects

A configuration manager, in addition to a top-level format object,
may now also know about a suite of sub-formats.  Top-level
configuration objects, in turn, may now have a suite of
sub-objects.
This commit is contained in:
Nick Mathewson 2019-07-24 11:20:55 -04:00
parent 38b770bbbb
commit 638e58379a
2 changed files with 90 additions and 17 deletions

View File

@ -73,10 +73,10 @@ managed_var_free_(managed_var_t *mv)
FREE_AND_NULL(managed_var_t, managed_var_free_, (mv)) FREE_AND_NULL(managed_var_t, managed_var_free_, (mv))
struct config_suite_t { struct config_suite_t {
/* NOTE: This object isn't implemented yet; it's just a placeholder /** A list of configuration objects managed by a given configuration
* to make sure we have our memory menagement right. * manager. They are stored in the same order as the config_format_t
*/ * objects in the manager's list of subformats. */
int foo; smartlist_t *configs;
}; };
/** /**
@ -86,6 +86,7 @@ static config_suite_t *
config_suite_new(void) config_suite_new(void)
{ {
config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t)); config_suite_t *suite = tor_malloc_zero(sizeof(config_suite_t));
suite->configs = smartlist_new();
return suite; return suite;
} }
@ -96,6 +97,7 @@ config_suite_free_(config_suite_t *suite)
{ {
if (!suite) if (!suite)
return; return;
smartlist_free(suite->configs);
tor_free(suite); tor_free(suite);
} }
@ -110,6 +112,11 @@ struct config_mgr_t {
* contains. A subsequent commit will add more. XXXX) * contains. A subsequent commit will add more. XXXX)
*/ */
const config_format_t *toplevel; const config_format_t *toplevel;
/**
* List of second-level configuration format objects that this manager
* also knows about.
*/
smartlist_t *subconfigs;
/** A smartlist of managed_var_t objects for all configuration formats. */ /** A smartlist of managed_var_t objects for all configuration formats. */
smartlist_t *all_vars; smartlist_t *all_vars;
/** A smartlist of config_abbrev_t objects for all abbreviations. These /** A smartlist of config_abbrev_t objects for all abbreviations. These
@ -137,12 +144,14 @@ config_mgr_t *
config_mgr_new(const config_format_t *toplevel_fmt) config_mgr_new(const config_format_t *toplevel_fmt)
{ {
config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t)); config_mgr_t *mgr = tor_malloc_zero(sizeof(config_mgr_t));
mgr->toplevel = toplevel_fmt; mgr->subconfigs = smartlist_new();
mgr->all_vars = smartlist_new(); mgr->all_vars = smartlist_new();
mgr->all_abbrevs = smartlist_new(); mgr->all_abbrevs = smartlist_new();
mgr->all_deprecations = smartlist_new(); mgr->all_deprecations = smartlist_new();
config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL); config_mgr_register_fmt(mgr, toplevel_fmt, IDX_TOPLEVEL);
mgr->toplevel = toplevel_fmt;
return mgr; return mgr;
} }
@ -158,6 +167,14 @@ config_mgr_register_fmt(config_mgr_t *mgr,
"Tried to add a format to a configuration manager after " "Tried to add a format to a configuration manager after "
"it had been frozen."); "it had been frozen.");
if (object_idx != IDX_TOPLEVEL) {
tor_assertf(fmt->config_suite_offset < 0,
"Tried to register a toplevel format in a non-toplevel position");
}
tor_assertf(fmt != mgr->toplevel &&
! smartlist_contains(mgr->subconfigs, fmt),
"Tried to register an already-registered format.");
/* register variables */ /* register variables */
for (i = 0; fmt->vars[i].member.name; ++i) { for (i = 0; fmt->vars[i].member.name; ++i) {
managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t)); managed_var_t *mv = tor_malloc_zero(sizeof(managed_var_t));
@ -182,6 +199,21 @@ config_mgr_register_fmt(config_mgr_t *mgr,
} }
} }
/**
* Add a new format to this configuration object. Asserts on failure.
*
**/
int
config_mgr_add_format(config_mgr_t *mgr,
const config_format_t *fmt)
{
tor_assert(mgr);
int idx = smartlist_len(mgr->subconfigs);
config_mgr_register_fmt(mgr, fmt, idx);
smartlist_add(mgr->subconfigs, (void *)fmt);
return idx;
}
/** Return a pointer to the config_suite_t * pointer inside a /** Return a pointer to the config_suite_t * pointer inside a
* configuration object; returns NULL if there is no such member. */ * configuration object; returns NULL if there is no such member. */
static inline config_suite_t ** static inline config_suite_t **
@ -204,10 +236,19 @@ config_mgr_get_suite_ptr(const config_mgr_t *mgr, void *toplevel)
static void * static void *
config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx) config_mgr_get_obj_mutable(const config_mgr_t *mgr, void *toplevel, int idx)
{ {
(void)mgr; tor_assert(mgr);
tor_assert(idx == IDX_TOPLEVEL); // nothing else is implemented yet XXXX
tor_assert(toplevel); tor_assert(toplevel);
if (idx == IDX_TOPLEVEL)
return toplevel; return toplevel;
tor_assertf(idx >= 0 && idx < smartlist_len(mgr->subconfigs),
"Index %d is out of range.", idx);
config_suite_t **suite = config_mgr_get_suite_ptr(mgr, toplevel);
tor_assert(suite);
tor_assert(smartlist_len(mgr->subconfigs) ==
smartlist_len((*suite)->configs));
return smartlist_get((*suite)->configs, idx);
} }
/** As config_mgr_get_obj_mutable(), but return a const pointer. */ /** As config_mgr_get_obj_mutable(), but return a const pointer. */
@ -257,6 +298,7 @@ config_mgr_free_(config_mgr_t *mgr)
smartlist_free(mgr->all_vars); smartlist_free(mgr->all_vars);
smartlist_free(mgr->all_abbrevs); smartlist_free(mgr->all_abbrevs);
smartlist_free(mgr->all_deprecations); smartlist_free(mgr->all_deprecations);
smartlist_free(mgr->subconfigs);
memset(mgr, 0, sizeof(*mgr)); memset(mgr, 0, sizeof(*mgr));
tor_free(mgr); tor_free(mgr);
} }
@ -296,6 +338,20 @@ config_mgr_assert_magic_ok(const config_mgr_t *mgr,
tor_assert(options); tor_assert(options);
tor_assert(mgr->frozen); tor_assert(mgr->frozen);
struct_check_magic(options, &mgr->toplevel_magic); struct_check_magic(options, &mgr->toplevel_magic);
config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, (void*)options);
if (suitep == NULL) {
tor_assert(smartlist_len(mgr->subconfigs) == 0);
return;
}
tor_assert(smartlist_len((*suitep)->configs) ==
smartlist_len(mgr->subconfigs));
SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
tor_assert(obj);
struct_check_magic(obj, &fmt->magic);
} SMARTLIST_FOREACH_END(fmt);
} }
/** Macro: assert that <b>cfg</b> has the right magic field for /** Macro: assert that <b>cfg</b> has the right magic field for
@ -309,12 +365,16 @@ void *
config_new(const config_mgr_t *mgr) config_new(const config_mgr_t *mgr)
{ {
tor_assert(mgr->frozen); tor_assert(mgr->frozen);
const config_format_t *fmt = mgr->toplevel; void *opts = tor_malloc_zero(mgr->toplevel->size);
void *opts = tor_malloc_zero(fmt->size);
struct_set_magic(opts, &mgr->toplevel_magic); struct_set_magic(opts, &mgr->toplevel_magic);
config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts); config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, opts);
if (suitep) { if (suitep) {
*suitep = config_suite_new(); *suitep = config_suite_new();
SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
void *obj = tor_malloc_zero(fmt->size);
struct_set_magic(obj, &fmt->magic);
smartlist_add((*suitep)->configs, obj);
} SMARTLIST_FOREACH_END(fmt);
} }
CONFIG_CHECK(mgr, opts); CONFIG_CHECK(mgr, opts);
return opts; return opts;
@ -826,30 +886,41 @@ config_reset(const config_mgr_t *mgr, void *options,
void void
config_free_(const config_mgr_t *mgr, void *options) config_free_(const config_mgr_t *mgr, void *options)
{ {
const config_format_t *fmt = mgr->toplevel;
if (!options) if (!options)
return; return;
tor_assert(fmt); tor_assert(mgr);
if (mgr->toplevel->clear_fn) { if (mgr->toplevel->clear_fn) {
mgr->toplevel->clear_fn(mgr, options); mgr->toplevel->clear_fn(mgr, options);
} }
config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options);
if (suitep) {
tor_assert(smartlist_len((*suitep)->configs) ==
smartlist_len(mgr->subconfigs));
SMARTLIST_FOREACH_BEGIN(mgr->subconfigs, const config_format_t *, fmt) {
void *obj = smartlist_get((*suitep)->configs, fmt_sl_idx);
if (fmt->clear_fn) {
fmt->clear_fn(mgr, obj);
}
} SMARTLIST_FOREACH_END(fmt);
}
SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) { SMARTLIST_FOREACH_BEGIN(mgr->all_vars, const managed_var_t *, mv) {
config_clear(mgr, options, mv); config_clear(mgr, options, mv);
} SMARTLIST_FOREACH_END(mv); } SMARTLIST_FOREACH_END(mv);
if (fmt->extra) { if (mgr->toplevel->extra) {
config_line_t **linep = STRUCT_VAR_P(options, fmt->extra->offset); config_line_t **linep = STRUCT_VAR_P(options,
mgr->toplevel->extra->offset);
config_free_lines(*linep); config_free_lines(*linep);
*linep = NULL; *linep = NULL;
} }
config_suite_t **suitep = config_mgr_get_suite_ptr(mgr, options); if (suitep) {
if (suitep) SMARTLIST_FOREACH((*suitep)->configs, void *, obj, tor_free(obj));
config_suite_free(*suitep); config_suite_free(*suitep);
}
tor_free(options); tor_free(options);
} }

View File

@ -76,6 +76,8 @@ typedef struct config_mgr_t config_mgr_t;
config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt); config_mgr_t *config_mgr_new(const config_format_t *toplevel_fmt);
void config_mgr_free_(config_mgr_t *mgr); void config_mgr_free_(config_mgr_t *mgr);
int config_mgr_add_format(config_mgr_t *mgr,
const config_format_t *fmt);
void config_mgr_freeze(config_mgr_t *mgr); void config_mgr_freeze(config_mgr_t *mgr);
#define config_mgr_free(mgr) \ #define config_mgr_free(mgr) \
FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr)) FREE_AND_NULL(config_mgr_t, config_mgr_free_, (mgr))