[asterisk-dev] [Code Review]: A new higher-level API for working with Asterisk configs, with example code in app_skel.c and udptl.c
Terry Wilson
reviewboard at asterisk.org
Tue May 15 16:10:45 CDT 2012
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > A few global comments:
> >
> > 1. Very nifty.
> > 2. This needs more doxygen comments.
> > 3. Before this goes in, it needs comprehensive unit tests. All of the behaviour of the framework is testable using the unit test framework.
> >
> > By far, the most difficult part of this framework - and probably the most 'easy' to get wrong aspect of this - is the relationship between what we are currently calling 'pvt' objects and 'pvt_config' objects. Part of that is because currently, for objects that would qualify as 'pvt' objects (sip_peer, ast_vm_user, etc.), those objects contain all of their configuration information in themselves. The idea that the configuration information lies in another object that has a different lifetime, e.g., during a reload that object is likely to be replaced, is tricky. People using the framework will have to be very careful recognizing the appropriate lifetime of their configuration object, such that operations occurring within that module get the appropriate configuration information throughout the entire lifetime of that operation, even if a reload happens.
> >
> > I'm not sure there's any easier way to do this then what we have, but its something to keep in mind going forward. We should attempt to make the relationship between the 'pvt' and 'pvt_config' as intuitive as possible, and make it as difficult as possible to create relationships that result in using 'new' configuration information after reloads on operations that already under way (or worse, reference leaks).
1. Glad you like it!
2. Doh. I thought I got everything. Looks like I need to add some stuff to .c files as well.
3. Indeed.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, line 178
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line178>
> >
> > From a coding guideline perspective, the '0' here is something of a magic number. If we had multiple objects in our ao2 global container, you could end up with things like:
> >
> > RAII_VAR(struct blah_config *, blah, ao2_global_obj_ref(globals, 3), ao2_cleanup);
> >
> > What says '3' is where blah is stored?
> >
> > If nothing else, that should be a #define:
> >
> > RAII_VAR(struct blah_config *, blah, ao2_global_obj_ref(globals, BLAH_CONFIG_INDEX), ao2_cleanup);
Richard and I have been discussing making ao2_global_obj_ref a single-object container. After he gets that done, this will go away.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, line 511
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line511>
> >
> > This is very cool. That is all.
yay!
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, lines 476-478
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line476>
> >
> > I do think it would be useful to have the framework allow for a callback function to be executed on a pvt when its related config object is updated. That way, during a configuration reload, only those objects whose configuration was changed would need to update themselves.
It's kind of a pain to tell outside the module that a particular object has not been updated. You would need to be able to compare every config field in the old config with the new config. You could approximate it by storing the old ast_config and comparing each variable in a category--but even then you have things like deleting a variable that was actually set to the default, or changing 'yes' to 'true'. It would look like something had changed, but it really hadn't, etc. The way you'd most likely have to do it is for types with default handlers to also have comparison callbacks and the ability to define comparators for custom types and register them.
But, keep in mind too that there really is no time that only an individual object is updated. When a reload happens, it is all or nothing. So there'd have to be some kind of queue of events that fires on a reload or something.
Also, I'm having trouble thinking of a situation where a private (SIP peer-like) object actually needs to "update" itself on a reload. Since the config data is separate from the private state, whenever something needs config-related data it can look it up and it will have the updated data. If at all possible, I think that configured objects should avoid needing updates on reload. If config-related information needs to be cached in the private to be used in some long-running transaction, then it shouldn't be the reload that triggers that information to be updated, but instead the fact that whatever transaction required the cache has ended.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, line 149
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line149>
> >
> > If this is for internal use only, you may want to create an opaque struct and hide the void *new_config on it.
Well, right now it is only kind of internal. :-/ The pre-apply callback might need to use it. I'll see about wrapping/hiding it.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, lines 175-182
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line175>
> >
> > How do we handle modules that use multiple configuration files, e.g., anything that uses users.conf?
We don't, yet. That is one of the things that I am going to work on. The general idea I have is to make filename into a files array. The files would be looped over in order over the same config objects. When registering options, you'd probably have to have to match on filename as well.
The way you would do it now if we weren't going to improve things is by manually parsing one of the files in the pre-link callback.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, line 255
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line255>
> >
> > I'd prefer an additional process config option as well, that would allow for passing in an in memory ast_config object. This would be particularly useful for unit testing, but could also be useful in things like app_voicemail, where meta data of voicemails is stored in ast_config objects and may potentially be manipulated prior to loading into in memory objects.
That could be interesting. I'll add it.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, lines 348-353
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line348>
> >
> > Use \code and \endcode around code samples (applies to all comments in this header)
Ok. I think 4 space indention is equivalent, but \code \encode makes it easier to see.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, line 435
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line435>
> >
> > Blob!
Doh!
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/utils.h, line 866
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27906#file27906line866>
> >
> > Put a comment on RAII_VAR describing its usage
Will do.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/astobj2.c, lines 717-720
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27908#file27908line717>
> >
> > This needs to complain loudly if this occurs. You may be safe in assigning NULL, but at the same time someone requested an object that either (a) doesn't exist in the global array, or (b) is past the bounds of the global array. Particularly in the latter case, that needs to warn the user that there's a potential misconfiguration of (or programmatic error in) the application.
This will become a non-issue when rmudgett makes un-arrayifies this.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/astobj2.c, lines 722-723
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27908#file27908line722>
> >
> > Again, complain if this occurs. Not getting the read lock would imply a pretty nasty problem, and future operations could fail spectacularly.
The underlying function complains loudly when it can't get the lock.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/config_options.c, lines 42-52
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27910#file27910line42>
> >
> > The internal private structures and methods preferably need some doxygen comments
Ok.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/config_options.c, lines 143-146
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27910#file27910line143>
> >
> > Complain loudly if this happens
Will do.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/config_options.c, lines 462-464
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27910#file27910line462>
> >
> > Mark with \internal
ok.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/udptl.c, lines 88-89
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27911#file27911line88>
> >
> > I think I had this on the previous review as well. These need to also be in the udptl_global_options struct.
They aren't config related, so they don't belong in the global options struct. That struct will get swapped out on reload and the debug values will get wiped out.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/udptl.c, lines 186-199
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27911#file27911line186>
> >
> > Since we're in here, may as well properly document all of these structs.
Will do.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/Makefile, line 197
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27899#file27899line197>
> >
> > No compiley on gcc 4.5.1. Need to check that the appropriate compiler version is in place before enabling this warning.
I'll see if I can figure out how to do that. I hate build system stuff.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, line 19
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line19>
> >
> > While we're here, we may as well update the location of the coding guidelines to point towards the asterisk.org wiki (there isn't a CODING_GUIDELINES in my checkout of trunk at any rate)
Done.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, lines 104-131
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line104>
> >
> > Even though this is a 'sample' application with dummy config objects, all of this needs doxygen comments (including the later functions, etc.). As it is, this app doesn't follow the coding guidelines it specifies in the header :-)
Ok.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, lines 126-131
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line126>
> >
> > This is probably one of the more confusing aspects of this change.
> >
> > Its not clear just from the example application what the purpose of this structure is, or how its related to skel_pvt_config. I imagine the idea here is to show how a private in memory object (such as a sip_peer or an ast_vm_user) can be populated from the configuration information in a file; in that case, this needs to be spelled out explicitly. You may also want to expand upon the information in skel_pvt to show more explicitly its relationship to skel_pvt_config. A few things that should be demonstrated:
> > * How to manage the lifetime of a skel_pvt's configuration and/or its information over multiple method calls
> > * How a skel_pvt should look up its configuration information
> >
> > Some of this is shown in the CLI command that iterates over the skel_pvt's, but given the concise nature of that example, its hard to understand all of the relationships between these two objects.
> >
The problem is that none of the stuff in app_skel *has* a purpose. It is all just made up and doesn't do anything. It makes it hard to write good examples. I'll see if I can think of something to make app_skel actually do that would involve some object lifetime issues, etc. app_skel is like Whose Line is it Anyway: everything's made up and the points don't matter.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, line 150
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line150>
> >
> > It would be nice if this demonstrated how to specify multiple entries in a white/black list
In my fleshing out of app_skel, I can see about adding multiple "global" categories. app_skel is going to end up with a crazier config than most real modules. At some point it might be better to direct people to real modules for more complex examples.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, lines 327-329
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line327>
> >
> > It doesn't appear as if this will link the created private back into the cfg->pvts container - and, unless I'm missing something, it should. Looking at what calls this, it doesn't appear as if it links the private back into the container as well (which it probably can't, since it doesn't know if what was returned was 'found' or 'created').
> >
> > I'm not sure I like dual purpose methods like this. I'd prefer the underlying calls to either find the object, or, if that fails, create it and link it back into cfg->pvt itself. That takes the burden off of the application writer to remember to link a created private into the underlying config structure.
This isn't supposed to do any linking. All it is supposed to do is return a reference to an existing or newly allocated private. As far as the back end is concerned, it just needs a ref to a private to add to the *newly created* container that will be swapped in if the reload is successful. We could separate it into two callbacks, but they each will be used exactly once in exactly the same place by the back end.
One argument for splitting them is that apps may already have these functions created and could just use the existing functions. In practice, this is not the case since the functions will have the wrong return types (have to return void *) and there isn't any automatic casting of function pointers. So if they did use them, they'd have to do a cast when assigning .find_pvt = xxx and that just seemed like asking for trouble. So, I felt that having a single type-correct find-or-create was better than having two other functions that would require either casts or wrappers and still only be used in once place, ever. It seemed much nicer for the user.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/apps/app_skel.c, lines 449-462
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27900#file27900line449>
> >
> > This example needs to demonstrate the recommended mechanism of tying a private and its config object together, and how a private should access its config object during in-flight operations. The access of the configuration object for the current instance of the private object should not be affected by a reload.
I still don't know if I like the idea of tying a config and its private together. The access of the configuration object in this case *won't* be affected by a reload because the reference we have is the reference to a snapshot of the config data and it is good for as long as we hold a ref to that object.
I think the best thing to do when you need some kind of state over a long period of time is to copy only that value into the peer-like object. Configuration != state. If tons of things in the configuration need to be kept around and not affected by reloads, then yes, a config data can be stored wherever as state. But looking at sip.conf as an example, most of the things in there are things we care about the value as it exists "right now" without regard to what the value was before.
It seems like most long-running things will have their own state that is completely independent of configurable objects like peers. SIP dialogs, for example.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/configs/app_skel.conf.sample, lines 15-20
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27901#file27901line15>
> >
> > In addition to having a pvt that contains no information, add a pvt that contains a subset of the allowed fields (such as only bit1 and bit2)
Will do.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, line 151
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line151>
> >
> > Why not use an AST_LIST here instead?
Because 1) types is read-only, has a defined size, and never needs to be appended to or deleted from and 2) it would make it impossible to initialize the aco_info via a designated initializer list. Users would have to do several AST_LIST_INSERT calls instead of just initializing everything all at once at the top of the file.
Basically, at one point I had a lot of alloc/init functions with really long argument lists. I still have some, but have tried to cut it down as much as possible.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/include/asterisk/config_options.h, lines 296-312
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27904#file27904line296>
> >
> > Is there a way to specify whether or not an option is required?
> >
> > We may have situations where we require an option to be in a configuration file, and do not want to provide a default value (if that's a bogus use case, feel free to discard this comment)
Currently you would do that via the pre-link (for private config objects) and pre-apply (for global config objects) callbacks. If the data doesn't make sense, return non-zero and the reload will be aborted.
Doing it in the backend is complicated because you then have to keep track of what options you've come across in a particular category check if any of the required ones weren't there. Much easier to check that something is set (and set appropriately) in the callbacks.
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/config_options.c, lines 189-209
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27910#file27910line189>
> >
> > We may want to use an AST_LIST traversal here instead - without a SENTINEL, this will seg fault. Since ensuring that a SENTINEL is placed on the end of the list is in the domain of the user of the framework, the current implementation allows for more coding errors then the AST_LIST macros would allow.
> >
> > Can we get into a situation where we don't get a match? If so, we should probably throw out a warning.
> >
> >
> >
As stated above, can't use designated initializers if we use AST_LIST. It would make it a bit more work for users to have to append each type to a list instead of just initializing it. It will most likely segfault immediately if someone doesn't include the sentinel, then it should be easy for them to catch.
What about just making a macro that just does it correctly. ACO_TYPES(...) { __VA_ARGS__, SENTINEL } and every example they will look at on how to do things will use that macro. .types = ACO_TYPES(general_opts, peer_opts), etc.?
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/config_options.c, lines 260-271
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27910#file27910line260>
> >
> > This feels odd. Why would we need a 'find_or_create_pvt', if we already failed to find it? Shouldn't we just need a 'create_pvt' option?
The find_pvt() call finds a private in a new container we just built--it is so we can detect duplicates in the container that we are building. It is more confusing looking than it needs to be because it isn't obvious that *fields is a container. The find_or_create_pvt callback looks for an existing pvt in the *running* config and returns its ref if it exists, otherwise allocates a new private that will be added to the new container.
I am open to some better names for these callbacks (and lots of other stuff).
> On May 15, 2012, 1:57 p.m., Matt Jordan wrote:
> > /trunk/main/udptl.c, lines 85-86
> > <https://reviewboard.asterisk.org/r/1873/diff/3/?file=27911#file27911line85>
> >
> > If these are going to be used in multiple implementation files (which I imagine they are), we may as well #define them in utils.h and give it a prefix of AST_.
Yeah, I think it exists other places as well.
- Terry
-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviewboard.asterisk.org/r/1873/#review6216
-----------------------------------------------------------
On May 15, 2012, 12:40 a.m., Terry Wilson wrote:
>
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviewboard.asterisk.org/r/1873/
> -----------------------------------------------------------
>
> (Updated May 15, 2012, 12:40 a.m.)
>
>
> Review request for Asterisk Developers.
>
>
> Summary
> -------
>
> This review supersedes the ones at reviews 1840 and 1841. There is still a lot of cleanup/documentation work to do. This review is mostly about the overall idea/method. Doing the finishing work before someone comes up with why it is all a bad idea seems like...a bad idea. If you want to comment on non-big-picture stuff, feel free, but most important at this stage is whether or not this is a good idea at all.
>
> The goal of this patch is to come up with a way to safely handle the loading and reloading a config data. Data should be consistent at all times, even if there is invalid data in the config file. Current modules tend to store the config-related data in private structures and modify it in-place as the config file is parsed. If there is a problem, the data is left in an inconsistent state.
>
> This solution decouples config-related data from the non-config-related state held in the various private structures. It should atomically swap the global, private, and private config-related data. It also adds a higher-level API for registering the various configuration options that exist at module load, with default callback handlers for common types and the ability to create custom handlers for other types. If the higher-level API is used, a few callback functions are defined and for the most part, config loading and reloading is done with a single function call. If the high-level API is not sufficient, it can either be modified as time-goes on, or a module can use the lower-level config option API functions themselves, keeping to the same overall format of swapping out config objects, etc. for thread safe reloads.
>
> This patch also makes significant use of the RAII_VAR macro which uses the gcc "cleanup" attribute to make sure that ref counts are cleaned up on return, etc.
>
> There needs to be a lot more documentation, unit tests, etc. But I should probably hold off on doing any of that until people have had a chance to look at the basic idea, etc. There are some configs that won't work with the high-level API as-is. Anything that uses categories that have the same name (chan_mobile) would need an option added that allows that. Things like ConfBridge with options that are user-definable DTMF codes would need a "catch-all" or pattern-matching for option names. Both would be fairly easy to implement.
>
> Rationale
> --------
> Why not store config data directly in the privates?
> Because updating the data at the time of parsing can leave things in an indeterminate state on reload.
>
> What about just storing the config data directly in the privates, and creating new privates as you parse and swap out for the old one?
> Swapping out the entire private structure would lose any non-config-related state in the private structure.
>
> What about using a copy function for the private's non-config-related state?
> Having to define(and keep it updated as new fields are added) a copy function for every private structure (and essentially for every type stored in that structure) that needs to properly handle reloads sounds like a huge pain to me.
>
> What about instead of having separate containers for privates and private configs, you just store a pointer to the private config in the private structure itself?
> There are two problems I see with this. 1) To ensure data is consistent when accessing multiple fields, one would need to hold a reference to the cfg in the private. But, since it is just a pointer, it encourages people to use it directly without grabbing a reference. By separating the containers, one must look up the config object and get a reference to it to be able to use it. 2) If there is a problem in the middle of switching out the cfg pointers, you end up with some privates with new configs and some with old.
>
> Overview of how it works: You basically have the global aco_info struct that defines information pertaining to the whole config. Then there are aco_types which define category-level things like regex for what categories are supported for the type, allocation/lookup functions, whether it is for a single global object, or objects in containers, etc. Below that are aco_options, which define the options available for a given type. For example:
>
> struct aco_info cfg_info = {
> .module = AST_MODULE,
> .filename = "app_skel.conf"
> .apply_config = skel_apply_config,
> .preload = {"general", SENTINEL }, /* If you need to load some contexts in order */
> };
>
> struct skel_global_cfg {
> ...
> };
>
> struct skel_pvt_cfg {
> ...
> };
>
> struct skel_pvt {
> ...
> };
>
> enum {
> GLOBAL_OPTIONS = 0,
> PVT_CFG_CONTAINER,
> PVT_CONTAINER,
> /* Must be declared last */
> NUM_GLOBAL_OBJECTS,
> };
> static AO2_GLOBAL_OBJ_STATIC(global_config, NUM_GLOBAL_OBJECTS);
> AST_MUTEX_DEFINE_STATIC(reload_lock);
>
> /* Required for global */
> void *skel_global_cfg_alloc(const char*cat);
>
> /* Required for privates (container-stored objects) */
> void *skel_pvt_cfg_alloc(const char *cat);
> void *skel_pvt_find_or_create(const char *cat);
> void *skel_pvt_find_in_container(struct ao2_container *cont, const char *cat);
> int skel_pvt_containers_alloc(struct ao2_container **newpvts, struct ao2_container **newcfgs);
>
> /* Optional for privates */
> int skel_pvt_cfg_post_init(void *cfg); /* Could be used to inherit global settings...ew. */
> int skel_pvt_cfg_pre_link(void *cfg); /* Could be used for final verification that things look a-ok */
>
> static int apply_config(void)
> {
> RAII_VAR(void *, new_global, aco_info_new_global_get(&cfg_info, "global"), ao2_cleanup);
> RAII_VAR(struct ao2_container *, new_pvts, aco_info_new_privates_get(&cfg_info, "private"), ao2_cleanup);
> RAII_VAR(struct ao2_container *, new_cfgs, aco_info_new_configs_get(&cfg_info, "private"), ao2_cleanup);
>
> if (!(new_global && new_pvts && new_cfgs)) {
> return -1;
> }
> /* Do any fixup for global configs here, individual privates could be fixed up via the pre-link callback */
>
> ao2_global_obj_replace_unref(global_config, GLOBAL_OPTIONS, new_global);
> ao2_global_obj_replace_unref(global_config, PVT_CONTAINER, new_pvts);
> ao2_global_obj_replace_unref(global_config, PVT_CFG_CONTAINER, new_cfgs);
>
> return 0;
> }
>
> static int process_config(int reload)
> {
> ast_mutex_lock(&reload_lock);
> if (aco_process_config(&cfg_info, reload)) {...};
> ast_mutex_unlock(&reload_lock);
> ...
> }
>
> static int reload(void)
> {
> if (process_config(1)) {...}
> }
> static int load_module(void)
> {
> ...
> aco_info_init(&cfg_info));
> global_type = aco_type_global_alloc("global", CONTEXT_ALLOW, "general", (aco_type_alloc) skel_global_alloc);
> priv_type = aco_type_private_alloc("private", CONTEXT_DENY, "general", NULL, NULL, (aco_type_alloc) skel_pvt_cfg_alloc, skel_containers_alloc, skel_find_or_create_pvt, skel_find_pvt, NULL, NULL)
>
> aco_type_register(&cfg_info, global_type);
> aco_type_register(&cfg_info, priv_type);
>
> aco_option_register(&cfg_info, "foo", global_type, "booya", OPT_STRINGFIELD_T, 0, STRFLDSET(struct skel_global_config, foo));
> ...
> if (process_config(0)) {...}
> ...
> }
>
>
> Diffs
> -----
>
> /trunk/Makefile 366506
> /trunk/apps/app_skel.c 366506
> /trunk/configs/app_skel.conf.sample PRE-CREATION
> /trunk/include/asterisk/astobj2.h 366506
> /trunk/include/asterisk/config.h 366506
> /trunk/include/asterisk/config_options.h PRE-CREATION
> /trunk/include/asterisk/stringfields.h 366506
> /trunk/include/asterisk/utils.h 366506
> /trunk/main/asterisk.exports.in 366506
> /trunk/main/astobj2.c 366506
> /trunk/main/config.c 366506
> /trunk/main/config_options.c PRE-CREATION
> /trunk/main/udptl.c 366506
>
> Diff: https://reviewboard.asterisk.org/r/1873/diff
>
>
> Testing
> -------
>
> Lots of testing with malloc debug, valgrind, etc.
>
>
> Thanks,
>
> Terry
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-dev/attachments/20120515/62783be4/attachment-0001.htm>
More information about the asterisk-dev
mailing list