Containers are data structures meant to store several objects, and perform various operations on them. Internally, objects are stored in lists, hash tables or other data structures depending on the needs.
Operations on container include:
- ao2_find(c, arg, flags) returns zero or more elements matching a given criteria (specified as arg). 'c' is the container pointer. Flags can be: OBJ_UNLINK - to remove the object, once found, from the container. OBJ_NODATA - don't return the object if found (no ref count change) OBJ_MULTIPLE - don't stop at first match OBJ_SEARCH_OBJECT - if set, 'arg' is an object pointer, and a hash table search will be done. If not, a traversal is done. OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object. Similar to OBJ_SEARCH_OBJECT and mutually exclusive. OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object. Similar to OBJ_SEARCH_KEY and mutually exclusive.
ao2_callback(c, flags, fn, arg) apply fn(obj, arg) to all objects in the container. Similar to find. fn() can tell when to stop, and do anything with the object including unlinking it.
- c is the container;
- flags can be OBJ_UNLINK - to remove the object, once found, from the container. OBJ_NODATA - don't return the object if found (no ref count change) OBJ_MULTIPLE - don't stop at first match OBJ_SEARCH_OBJECT - if set, 'arg' is an object pointer, and a hash table search will be done. If not, a traversal is done through all the hash table 'buckets'.. OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object. Similar to OBJ_SEARCH_OBJECT and mutually exclusive. OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object. Similar to OBJ_SEARCH_KEY and mutually exclusive.
- fn is a func that returns int, and takes 3 args: (void *obj, void *arg, int flags); obj is an object arg is the same as arg passed into ao2_callback flags is the same as flags passed into ao2_callback fn returns: 0: no match, keep going CMP_STOP: stop search, no match CMP_MATCH: This object is matched.
Note that the entire operation is run with the container locked, so nobody else can change its content while we work on it. However, we pay this with the fact that doing anything blocking in the callback keeps the container blocked. The mechanism is very flexible because the callback function fn() can do basically anything e.g. counting, deleting records, etc. possibly using arg to store the results.
- iterate on a container this is done with the following sequence
void *o;
... do something on o ...
}
#define ao2_iterator_next(iter)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
The difference with the callback is that the control
on how to iterate is left to us.
- \b ao2_ref(c, -1)
dropping a reference to a container destroys it, very simple!
Containers are ao2 objects themselves, and this is why their implementation is simple too.
Before declaring containers, we need to declare the types of the arguments passed to the constructor - in turn, this requires to define callback and hash functions and their arguments.