[asterisk-commits] twilson: branch twilson/config_work r366464 - in /team/twilson/config_work: a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon May 14 17:14:31 CDT 2012


Author: twilson
Date: Mon May 14 17:14:26 2012
New Revision: 366464

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=366464
Log:
Check in work to avoid race condition when querying config objects

Instead of storing and swapping out the config objects indivdually and
possibly getting a reload in between a request for a privates container
and the private config info container, store all of the config objects
in a single object that we swap out and get back. This object represents
a snapshot of all config data so that everything is 100% consistent.

Modified:
    team/twilson/config_work/apps/app_skel.c
    team/twilson/config_work/include/asterisk/config_options.h
    team/twilson/config_work/main/config_options.c
    team/twilson/config_work/main/udptl.c

Modified: team/twilson/config_work/apps/app_skel.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/apps/app_skel.c?view=diff&rev=366464&r1=366463&r2=366464
==============================================================================
--- team/twilson/config_work/apps/app_skel.c (original)
+++ team/twilson/config_work/apps/app_skel.c Mon May 14 17:14:26 2012
@@ -130,47 +130,42 @@
 	size_t non_config_state;
 };
 
-enum {
-	GLOBAL_OPTIONS = 0,
-	PVT_CFG_CONTAINER,
-	PVT_CONTAINER,
-
-	/* Must be declared last */
-	NUM_GLOBAL_OBJECTS,
-};
-
 #define PVT_BUCKETS 17
 
-static void *skel_global_alloc(const char *cat);
+struct skel_config {
+	struct skel_global_config *general;
+	struct ao2_container *pvts;
+	struct ao2_container *cfgs;
+};
+
+static void *skel_config_alloc(void);
 static void *skel_pvt_cfg_alloc(const char *cat);
-static int skel_containers_alloc(struct ao2_container **newpvts, struct ao2_container **newcfgs);
 static void *skel_find_or_create_pvt(const char *category);
 static void *skel_find_pvt(struct ao2_container *tmp_container, const char *category);
 
 static struct aco_type general_options = {
 	.type = ACO_GLOBAL_OBJ,
-	.global_index = GLOBAL_OPTIONS,
+	.cfg_offset = offsetof(struct skel_config, general),
 	.category_allow = ACO_WHITELIST,
 	.category = "general",
-	.cfg_alloc = skel_global_alloc,
 };
 
 static struct aco_type private_options = {
 	.type = ACO_PRIVATE_OBJ,
-	.pvt_index = PVT_CONTAINER,
-	.cfg_index = PVT_CFG_CONTAINER,
 	.category_allow = ACO_BLACKLIST,
 	.category = "general",
 	.cfg_alloc = skel_pvt_cfg_alloc,
-	.containers_alloc = skel_containers_alloc,
 	.find_or_create_pvt = skel_find_or_create_pvt,
 	.find_pvt = skel_find_pvt,
-};
-
-static AO2_GLOBAL_OBJ_STATIC(globals, NUM_GLOBAL_OBJECTS);
+	.pvt_offset = offsetof(struct skel_config, pvts),
+	.cfg_offset = offsetof(struct skel_config, cfgs),
+};
+
+static AO2_GLOBAL_OBJ_STATIC(globals, 1);
 
 CONFIG_INFO_STANDARD(cfg_info, "app_skel.conf", globals,
 	.types = { &general_options, &private_options, NULL },
+	.snapshot_alloc = skel_config_alloc,
 );
 
 static void skel_global_config_destructor(void *obj)
@@ -179,19 +174,19 @@
 	ast_string_field_free_memory(cfg);
 }
 
-static void skel_pvt_cfg_unlink(struct skel_pvt_config *cfg)
-{
-	RAII_VAR(struct ao2_container *, cfgs, ao2_global_obj_ref(globals, PVT_CFG_CONTAINER), ao2_cleanup);
-	if (cfgs) {
-		ao2_unlink(cfgs, cfg);
+static void skel_pvt_cfg_unlink(struct skel_pvt_config *pcfg)
+{
+	RAII_VAR(struct skel_config *, cfg, ao2_global_obj_ref(globals, 0), ao2_cleanup);
+	if (cfg && cfg->cfgs) {
+		ao2_unlink(cfg->cfgs, pcfg);
 	}
 }
 
 static struct skel_pvt_config *skel_pvt_find_cfg(struct skel_pvt *pvt)
 {
-	RAII_VAR(struct ao2_container *, cfgs, ao2_global_obj_ref(globals, PVT_CFG_CONTAINER), ao2_cleanup);
-	if (cfgs) {
-		return ao2_find(cfgs, pvt->name, OBJ_KEY);
+	RAII_VAR(struct skel_config *, cfg, ao2_global_obj_ref(globals, 0), ao2_cleanup);
+	if (cfg && cfg->cfgs) {
+		return ao2_find(cfg->cfgs, pvt->name, OBJ_KEY);
 	}
 
 	return NULL;
@@ -239,19 +234,6 @@
 	struct skel_pvt_config *one = obj, *two = arg;
 	const char *match = (flags & OBJ_KEY) ? arg : two->name;
 	return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-static int skel_containers_alloc(struct ao2_container **newpvts, struct ao2_container **newcfgs)
-{
-	if (!(*newpvts = ao2_container_alloc(PVT_BUCKETS, skel_pvt_hash, skel_pvt_cmp))) {
-		return -1;
-	}
-	if (!(*newcfgs = ao2_container_alloc(PVT_BUCKETS, skel_pvt_config_hash, skel_pvt_config_cmp))) {
-		ao2_ref(*newpvts, -1);
-		*newpvts = NULL;
-		return -1;
-	}
-	return 0;
 }
 
 /*! \brief A custom bitfield handler
@@ -341,9 +323,9 @@
 
 static void *skel_find_or_create_pvt(const char *category)
 {
-	RAII_VAR(struct ao2_container *, pvt_container, ao2_global_obj_ref(globals, PVT_CONTAINER), ao2_cleanup);
+	RAII_VAR(struct skel_config *, cfg, ao2_global_obj_ref(globals, 0), ao2_cleanup);
 	void *obj;
-	if (!pvt_container || !(obj = ao2_find(pvt_container, category, OBJ_KEY))) {
+	if (!cfg || !cfg->pvts || !(obj = ao2_find(cfg->pvts, category, OBJ_KEY))) {
 		return skel_pvt_alloc(category);
 	}
 	return obj;
@@ -372,30 +354,48 @@
 	return pvtcfg;
 }
 
-static void *skel_global_alloc(const char *cat)
-{
-	struct skel_global_config *cfg;
-
-	if (cat) {
+static void skel_config_destructor(void *obj)
+{
+	struct skel_config *cfg = obj;
+	ao2_cleanup(cfg->general);
+	ao2_cleanup(cfg->pvts);
+	ao2_cleanup(cfg->cfgs);
+}
+
+static void *skel_config_alloc(void)
+{
+	struct skel_config *cfg;
+
+	if (!(cfg = ao2_alloc(sizeof(*cfg), skel_config_destructor))) {
 		return NULL;
 	}
 
 	/* Allocate/initialize memory */
-	if (!(cfg = ao2_alloc(sizeof(*cfg), skel_global_config_destructor))) {
-		return NULL;
-	}
-
-	if (ast_string_field_init(cfg, 128)) {
-		ao2_ref(cfg, -1);
-		return NULL;
+	if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), skel_global_config_destructor))) {
+		goto error;
+	}
+
+	if (ast_string_field_init(cfg->general, 128)) {
+		goto error;
+	}
+
+	if (!(cfg->pvts = ao2_container_alloc(PVT_BUCKETS, skel_pvt_hash, skel_pvt_cmp))) {
+		goto error;
+	}
+
+	if (!(cfg->cfgs = ao2_container_alloc(PVT_BUCKETS, skel_pvt_config_hash, skel_pvt_config_cmp))) {
+		goto error;
 	}
 
 	return cfg;
+error:
+	ao2_ref(cfg, -1);
+	return NULL;
 }
 
 static char *handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct skel_global_config *, cfg, NULL, ao2_cleanup);
+	RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
 
 	switch(cmd) {
 	case CLI_INIT:
@@ -408,23 +408,22 @@
 		return NULL;
 	}
 
-	if (!(cfg = ao2_global_obj_ref(globals, GLOBAL_OPTIONS))) {
-		return NULL;
-	}
-
-	ast_cli(a->fd, "foo:      %s\n", cfg->foo);
-	ast_cli(a->fd, "bar:      %s\n", cfg->bar);
-	ast_cli(a->fd, "baz:      %s\n", cfg->baz);
-	ast_cli(a->fd, "blah:     %s\n", AST_CLI_YESNO(cfg->blah));
-	ast_cli(a->fd, "bindaddr: %s\n", ast_sockaddr_stringify(&cfg->bindaddr));
+	if (!(cfg = ao2_global_obj_ref(globals, 0)) || !cfg->general) {
+		return NULL;
+	}
+
+	ast_cli(a->fd, "foo:      %s\n", cfg->general->foo);
+	ast_cli(a->fd, "bar:      %s\n", cfg->general->bar);
+	ast_cli(a->fd, "baz:      %s\n", cfg->general->baz);
+	ast_cli(a->fd, "blah:     %s\n", AST_CLI_YESNO(cfg->general->blah));
+	ast_cli(a->fd, "bindaddr: %s\n", ast_sockaddr_stringify(&cfg->general->bindaddr));
 
 	return CLI_SUCCESS;
 }
 
 static char *handle_skel_show_pvts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct ao2_container *, pvts, NULL, ao2_cleanup);
-	RAII_VAR(struct ao2_container *, cfgs, NULL, ao2_cleanup);
+	RAII_VAR(struct skel_config *, cfg, NULL, ao2_cleanup);
 	struct ao2_iterator iter;
 	struct skel_pvt *pvt;
 	char codec_buf[128];
@@ -440,29 +439,25 @@
 		return NULL;
 	}
 
-	if (!(pvts = ao2_global_obj_ref(globals, PVT_CONTAINER))) {
-		return NULL;
-	}
-	if (!(cfgs = ao2_global_obj_ref(globals, PVT_CFG_CONTAINER))) {
-		ao2_ref(pvts, -1);
+	if (!(cfg = ao2_global_obj_ref(globals, 0)) || !(cfg->cfgs && cfg->pvts)) {
 		return NULL;
 	}
 
 #define SKEL_FORMAT "%-15.15s %-25.25s %-20.20s %-5.5s %-5.5s %-5.5s %-2.2s\n"
 #define SKEL_FORMAT1 "%-15.15s %-25.25s %-20.20s %-5.5s %-5.5s %-5.5s %-2.2zu\n"
 	ast_cli(a->fd, SKEL_FORMAT, "Name", "Description", "Codecs", "ACL", "Bit1", "Bit2", "N");
-	iter = ao2_iterator_init(pvts, 0);
+	iter = ao2_iterator_init(cfg->pvts, 0);
 	while ((pvt = ao2_iterator_next(&iter))) {
-		RAII_VAR(struct skel_pvt_config *, cfg, NULL, ao2_cleanup);
-		if (!(cfg = ao2_find(cfgs, pvt->name, OBJ_KEY))) {
+		RAII_VAR(struct skel_pvt_config *, pcfg, NULL, ao2_cleanup);
+		if (!(pcfg = ao2_find(cfg->cfgs, pvt->name, OBJ_KEY))) {
 			ast_log(LOG_NOTICE, "Could not find config info for %s\n", pvt->name);
 			ao2_ref(pvt, -1);
 			continue;
 		}
 		/* As an example of non-config-related state remaining between reloads */
 		++pvt->non_config_state;
-		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, cfg->caps);
-		ast_cli(a->fd, SKEL_FORMAT1, pvt->name, cfg->description, codec_buf, AST_CLI_YESNO(cfg->permit != NULL), AST_CLI_YESNO(cfg->bit1), AST_CLI_YESNO(cfg->bit2), pvt->non_config_state);
+		ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, pcfg->caps);
+		ast_cli(a->fd, SKEL_FORMAT1, pvt->name, pcfg->description, codec_buf, AST_CLI_YESNO(pcfg->permit != NULL), AST_CLI_YESNO(pcfg->bit1), AST_CLI_YESNO(pcfg->bit2), pvt->non_config_state);
 		ao2_ref(pvt, -1);
 	}
 	ao2_iterator_destroy(&iter);

Modified: team/twilson/config_work/include/asterisk/config_options.h
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/include/asterisk/config_options.h?view=diff&rev=366464&r1=366463&r2=366464
==============================================================================
--- team/twilson/config_work/include/asterisk/config_options.h (original)
+++ team/twilson/config_work/include/asterisk/config_options.h Mon May 14 17:14:26 2012
@@ -115,9 +115,8 @@
 	const char *matchvalue; /*!< The value of the option to require for matching (i.e. 'peer' for type= in sip.conf) */
 	regex_t *regex;
 	enum aco_category_op category_allow; /*!< Whether the following category regex is a whitelist or blacklist */
-	size_t global_index;      /*!< The index in the global object array for the global config */
-	size_t pvt_index;         /*!< The index in the global object array for the private container */
-	size_t cfg_index;         /*!< The index in the global object array for the private config container */
+	size_t cfg_offset;         /*!< The offset in the config snapshot for the global config or private config container */
+	size_t pvt_offset;         /*!< The index in the global object array for the private container */
 	aco_type_alloc cfg_alloc; /*!< An allocation function for ao2 object associated with this type */
 
 	/* non-global callbacks */
@@ -134,13 +133,20 @@
  */
 typedef int (*aco_pre_apply_config)(void);
 
+/*! \brief A callback functino for allocating an object to hold all config objects
+ * \retval NULL error
+ * \retval non-NULL a config object container
+ */
+typedef void *(*aco_snapshot_alloc)(void);
+
 struct aco_info {
 	const char *module;         /*!< The name of the module whose config is being processed */
 	const char *filename;       /*!< The config filename */
 	struct ao2_container *opts; /*!< Internal use - options to parse */
 	aco_pre_apply_config pre_apply_config; /*!< A callback called after processing, but before changes are applied */
-	struct ao2_global_obj *current_array;  /*!< The module's global object array for this config */
-	void **new_array;         /*!< Internal use - A cache of new config objects to be applied */
+	aco_snapshot_alloc snapshot_alloc;     /*!< Allocate an object to hold all global configs and private containers */
+	void *global_obj;         /*!< The global object array that hold the config object */
+	void *new_config;         /*!< Internal use - A cache of newly created config */
 	const char **preload;     /*!< Categories to parse first. Do something like char *arr[] = {"general", NULL}; and do .preload = arr */
 	struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */
 };
@@ -166,7 +172,7 @@
 static struct aco_info name = { \
 	.module = AST_MODULE, \
 	.filename = fn, \
-	.current_array = &arr.global, \
+	.global_obj = &arr.global, \
 	__VA_ARGS__ \
 };
 

Modified: team/twilson/config_work/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/main/config_options.c?view=diff&rev=366464&r1=366463&r2=366464
==============================================================================
--- team/twilson/config_work/main/config_options.c (original)
+++ team/twilson/config_work/main/config_options.c Mon May 14 17:14:26 2012
@@ -180,55 +180,6 @@
 	return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
 }
 
-static int allocate_temp_objects(struct aco_info *info)
-{
-	struct aco_type *t;
-	size_t x;
-
-	for (x = 0, t = info->types[x]; t; t = info->types[++x]) {
-		switch (t->type) {
-		case ACO_GLOBAL_OBJ:
-			if (!(info->new_array[t->global_index] = t->cfg_alloc(NULL))) {
-				return -1;
-			}
-			break;
-		case ACO_PRIVATE_OBJ:
-			if (t->containers_alloc((struct ao2_container **) &info->new_array[t->pvt_index], (struct ao2_container **) &info->new_array[t->cfg_index])) {
-				return -1;
-			}
-			break;
-		}
-	}
-	return 0;
-}
-
-static void cleanup_temp_objects(struct aco_info *info)
-{
-	struct aco_type *t;
-	size_t x;
-
-	for (x = 0, t = info->types[x]; t; t = info->types[++x]) {
-		switch (t->type) {
-		case ACO_GLOBAL_OBJ:
-			if (info->new_array[t->global_index]) {
-				ao2_ref(info->new_array[t->global_index], -1);
-				info->new_array[t->global_index] = NULL;
-			}
-			break;
-		case ACO_PRIVATE_OBJ:
-			if (info->new_array[t->pvt_index]) {
-				ao2_ref(info->new_array[t->pvt_index], -1);
-				info->new_array[t->pvt_index] = NULL;
-			}
-			if (info->new_array[t->cfg_index]) {
-				ao2_ref(info->new_array[t->cfg_index], -1);
-				info->new_array[t->cfg_index] = NULL;
-			}
-			break;
-		}
-	}
-}
-
 static struct aco_type *internal_aco_type_find(struct aco_info *info, struct ast_config *cfg, const char *category)
 {
 	size_t x;
@@ -291,19 +242,21 @@
 	}
 
 	/* if type == GLOBAL_OBJ, set defaults and configure the cached cfg object */
-	if (obj->type == ACO_GLOBAL_OBJ && info->new_array[obj->global_index]) {
-		if (aco_set_defaults(info->opts, cat, info->new_array[obj->global_index])) {
+	if (obj->type == ACO_GLOBAL_OBJ && info->new_config + obj->cfg_offset) {
+		void **pretend = info->new_config + obj->cfg_offset;
+		if (aco_set_defaults(info->opts, cat, *pretend)) {
 			ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", info->filename, cat);
 			return -1;
 		}
-		if (aco_process_category_options(info->opts, cfg, cat, info->new_array[obj->global_index])) {
+		if (aco_process_category_options(info->opts, cfg, cat, *pretend)) {
 			ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", info->filename, cat);
 			return -1;
 		}
 	} else if (obj->type == ACO_PRIVATE_OBJ) {
+		void **pretend = info->new_config + obj->pvt_offset;
 		/* If we've already linked a private for cat in newpvts, don't add a second one with the same name */
-		if (info->new_array[obj->pvt_index]) {
-			if ((tmppvt = obj->find_pvt(info->new_array[obj->pvt_index], cat))) {
+		if (*pretend) {
+			if ((tmppvt = obj->find_pvt(*pretend, cat))) {
 				ast_log(LOG_ERROR, "In %s: Multiple definitions of %s!\n", info->filename, cat);
 				return -1;
 			}
@@ -343,11 +296,12 @@
 		}
 
 		/* We have a valid pvt/cfg, link 'em */
-		if (tmppvt && !ao2_link(info->new_array[obj->pvt_index], tmppvt)) {
+		if (tmppvt && !ao2_link(*pretend, tmppvt)) {
 			ast_log(LOG_ERROR, "In %s: Linking private for %s failed\n", info->filename, cat);
 			return -1;
 		}
-		if (!ao2_link(info->new_array[obj->cfg_index], tmpcfg)) {
+		pretend = info->new_config + obj->cfg_offset;
+		if (!ao2_link(*pretend, tmpcfg)) {
 			ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", info->filename, cat);
 			return -1;
 		}
@@ -357,13 +311,7 @@
 
 static int apply_config(struct aco_info *info)
 {
-	size_t x;
-
-	__ao2_global_obj_wrlock(info->current_array, __FILE__, __LINE__, __PRETTY_FUNCTION__, "info->current_array");
-	for (x = 0; x < info->current_array->num_elements; x++) {
-		__ao2_global_obj_replace_unref(info->current_array, x, info->new_array[x], 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, "unused");
-	}
-	__ao2_global_obj_unlock(info->current_array, __FILE__, __LINE__, __PRETTY_FUNCTION__, "info->current_array");
+	__ao2_global_obj_replace_unref(info->global_obj, 0, info->new_config, 1, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, "info->global_obj");
 
 	return 0;
 }
@@ -394,7 +342,7 @@
 		return -1;
 	}
 
-	if (allocate_temp_objects(info)) {
+	if (!(info->new_config = info->snapshot_alloc())) {
 		ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->filename);
 		goto error;
 	}
@@ -421,13 +369,13 @@
 	}
 
 	res = apply_config(info); /* The module already knows where the objects are */
-	cleanup_temp_objects(info);
+	ao2_ref(info->new_config, -1);
 
 	return res;
 
 error:
 	ast_config_destroy(cfg);
-	cleanup_temp_objects(info);
+	ao2_ref(info->new_config, -1);
 	return -1;
 }
 
@@ -499,11 +447,6 @@
 		}
 	}
 
-	if (!(info->new_array = ast_calloc(info->current_array->num_elements, sizeof(info->new_array)))) {
-		ao2_ref(info->opts, -1);
-		info->opts = NULL;
-		return -1;
-	}
 	return 0;
 }
 
@@ -513,7 +456,6 @@
 		ao2_ref(info->opts, -1);
 	}
 	internal_info_types_destroy(info);
-	ast_free(info->new_array);
 }
 
 /*! \brief match for anything where the category passes (or fails if !category_allow) the category regex
@@ -629,7 +571,7 @@
 	return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
 }
 
-/* opt->args[0] = ast_string_field,  opt->args[1] = field_mgr_pool, opt->args[2] = field_mgri */
+/* opt->args[0] = ast_string_field,  opt->args[1] = field_mgr_pool, opt->args[2] = field_mgr */
 int ast_config_option_stringfield_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
 	ast_string_field *field = (const char **)(obj + opt->args[0]);

Modified: team/twilson/config_work/main/udptl.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/main/udptl.c?view=diff&rev=366464&r1=366463&r2=366464
==============================================================================
--- team/twilson/config_work/main/udptl.c (original)
+++ team/twilson/config_work/main/udptl.c Mon May 14 17:14:26 2012
@@ -195,19 +195,22 @@
 
 static AO2_GLOBAL_OBJ_STATIC(globals, UDPTL_NUM_GLOBALS);
 
-static void *udptl_cfg_alloc(const char *unused);
+struct udptl_config {
+	struct udptl_global_options *general;
+};
+
+static void *udptl_snapshot_alloc(void);
 static int udptl_pre_apply_config(void);
 
 static struct aco_type general_options = {
 	.type = ACO_GLOBAL_OBJ,
-	.global_index = UDPTL_GENERAL, 
 	.category_allow = ACO_WHITELIST,
 	.category = "general",
-	.cfg_alloc = udptl_cfg_alloc,
 };
 
 CONFIG_INFO_STANDARD(cfg_info, "udptl.conf", globals,
 	.types = { &general_options, NULL },
+	.snapshot_alloc = udptl_snapshot_alloc,
 	.pre_apply_config = udptl_pre_apply_config,
 );
 
@@ -951,9 +954,9 @@
 	int startplace;
 	int i;
 	long int flags;
-	RAII_VAR(struct udptl_global_options *, opts, ao2_global_obj_ref(globals, UDPTL_GENERAL), ao2_cleanup);
-
-	if (!opts) {
+	RAII_VAR(struct udptl_config *, cfg, ao2_global_obj_ref(globals, 0), ao2_cleanup);
+
+	if (!cfg || !cfg->general) {
 		ast_log(LOG_ERROR, "Could not access global udptl options!\n");
 		return NULL;
 	}
@@ -962,8 +965,8 @@
 		return NULL;
 	}
 
-	udptl->error_correction_span = opts->fecspan;
-	udptl->error_correction_entries = opts->fecentries;
+	udptl->error_correction_span = cfg->general->fecspan;
+	udptl->error_correction_entries = cfg->general->fecentries;
 
 	udptl->far_max_datagram = -1;
 	udptl->far_max_ifp = -1;
@@ -985,13 +988,13 @@
 	fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK);
 
 #ifdef SO_NO_CHECK
-	if (opts->nochecksums)
-		setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &opts->nochecksums, sizeof(opts->nochecksums));
+	if (cfg->general->nochecksums)
+		setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &cfg->general->nochecksums, sizeof(cfg->general->nochecksums));
 #endif
 
 	/* Find us a place */
-	x = (opts->start == opts->end) ? opts->start : (ast_random() % (opts->end - opts->start)) + opts->start;
-	if (opts->use_even_ports && (x & 1)) {
+	x = (cfg->general->start == cfg->general->end) ? cfg->general->start : (ast_random() % (cfg->general->end - cfg->general->start)) + cfg->general->start;
+	if (cfg->general->use_even_ports && (x & 1)) {
 		++x;
 	}
 	startplace = x;
@@ -1007,13 +1010,13 @@
 			ast_free(udptl);
 			return NULL;
 		}
-		if (opts->use_even_ports) {
+		if (cfg->general->use_even_ports) {
 			x += 2;
 		} else {
 			++x;
 		}
-		if (x > opts->end)
-			x = opts->start;
+		if (x > cfg->general->end)
+			x = cfg->general->start;
 		if (x == startplace) {
 			ast_log(LOG_WARNING, "No UDPTL ports remaining\n");
 			close(udptl->fd);
@@ -1344,7 +1347,7 @@
 
 static char *handle_cli_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct udptl_global_options *, opts, NULL, ao2_cleanup);
+	RAII_VAR(struct udptl_config *, cfg, NULL, ao2_cleanup);
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -1357,18 +1360,18 @@
 		return NULL;
 	}
 
-	if (!(opts = ao2_global_obj_ref(globals, UDPTL_GENERAL))) {
+	if (!(cfg = ao2_global_obj_ref(globals, 0))) {
 		return CLI_FAILURE;
 	}
 
 	ast_cli(a->fd, "UDPTL Global options\n");
 	ast_cli(a->fd, "--------------------\n");
-	ast_cli(a->fd, "udptlstart:      %u\n", opts->start);
-	ast_cli(a->fd, "udptlend:        %u\n", opts->end);
-	ast_cli(a->fd, "udptlfecentries: %u\n", opts->fecentries);
-	ast_cli(a->fd, "udptlfecspan:    %u\n", opts->fecspan);
-	ast_cli(a->fd, "use_even_ports:  %s\n", AST_CLI_YESNO(opts->use_even_ports));
-	ast_cli(a->fd, "udptlchecksums: %s\n", AST_CLI_YESNO(!opts->nochecksums));
+	ast_cli(a->fd, "udptlstart:      %u\n", cfg->general->start);
+	ast_cli(a->fd, "udptlend:        %u\n", cfg->general->end);
+	ast_cli(a->fd, "udptlfecentries: %u\n", cfg->general->fecentries);
+	ast_cli(a->fd, "udptlfecspan:    %u\n", cfg->general->fecspan);
+	ast_cli(a->fd, "use_even_ports:  %s\n", AST_CLI_YESNO(cfg->general->use_even_ports));
+	ast_cli(a->fd, "udptlchecksums: %s\n", AST_CLI_YESNO(!cfg->general->nochecksums));
 
 	return CLI_SUCCESS;
 }
@@ -1378,15 +1381,25 @@
 	AST_CLI_DEFINE(handle_cli_show_config, "Show UDPTL config options"),
 };
 
-static void *udptl_cfg_alloc(const char *unused)
-{
-	struct udptl_global_options *opts;
-
-	if (!(opts = ao2_alloc(sizeof(*opts), NULL))) {
+static void udptl_config_destructor(void *obj)
+{
+	struct udptl_config *cfg = obj;
+	ao2_cleanup(cfg->general);
+}
+
+static void *udptl_snapshot_alloc(void)
+{
+	struct udptl_config *cfg;
+
+	if (!(cfg = ao2_alloc(sizeof(*cfg), udptl_config_destructor))) {
 		return NULL;
 	}
-
-	return opts;
+	if (!(cfg->general = ao2_alloc(sizeof(*cfg->general), NULL))) {
+		ao2_ref(cfg, -1);
+		return NULL;
+	}
+
+	return cfg;
 }
 
 static int removed_options_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
@@ -1407,7 +1420,8 @@
 }
 
 static int udptl_pre_apply_config(void) {
-	struct udptl_global_options * new_global = cfg_info.new_array[UDPTL_GENERAL];
+	struct udptl_config *cfg = cfg_info.new_config;
+	struct udptl_global_options *new_global = cfg->general;
 
 	if (!new_global) {
 		return -1;
@@ -1435,13 +1449,6 @@
 		ast_log(LOG_NOTICE, "Odd numbered udptlend specified but use_even_ports enabled. udptlend is now %d\n", new_global->end);
 	}
 
-	/* Replace existing config */
-	if (ao2_global_obj_replace_unref(globals, UDPTL_GENERAL, new_global)) {
-		ast_verb(2, "UDPTL allocating from port range %d -> %d via reload\n", new_global->start, new_global->end);
-	} else {
-		ast_verb(2, "UDPTL allocating from port range %d -> %d via intial load\n", new_global->start, new_global->end);
-	}
-
 	return 0;
 }
 




More information about the asterisk-commits mailing list