Asterisk - The Open Source Telephony Project GIT-master-f36a736
|
This module implements an abstraction for objects (with locks and reference counts), and containers for these user-defined objects, also supporting locking, reference counting and callbacks.
The internal implementation of objects and containers is opaque to the user, so we can use different data structures as needs arise.
An ao2 object is a block of memory that the user code can access, and for which the system keeps track (with a bit of help from the programmer) of the number of references around. When an object has no more references (refcount == 0), it is destroyed, by first invoking whatever 'destructor' function the programmer specifies (it can be NULL if none is necessary), and then freeing the memory. This way objects can be shared without worrying who is in charge of freeing them. As an additional feature, ao2 objects are associated to individual locks.
Creating an object requires the size of the object and a pointer to the destructor function:
struct foo *o; o = ao2_alloc(sizeof(struct foo), my_destructor_fn);
The value returned points to the user-visible portion of the objects (user-data), but is also used as an identifier for all object-related operations such as refcount and lock manipulations.
On return from ao2_alloc():
we cannot call free(o) to dispose of the object. Rather, we tell the system that we do not need the reference anymore:
ao2_ref(o, -1)
causing the destructor to be called (and then memory freed) when the refcount goes to 0.
ao2_ref(o, +1) can be used to modify the refcount on the object in case we want to pass it around.
ao2_lock(obj), ao2_unlock(obj), ao2_trylock(obj) can be used to manipulate the lock associated with the object.
An ao2 container is an abstract data structure where we can store ao2 objects, search them (hopefully in an efficient way), and iterate or apply a callback function to them. A container is just an ao2 object itself.
A container must first be allocated, specifying the initial parameters. At the moment, this is done as follows:
<b>Sample Usage:</b> \code struct ao2_container *c; c = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_BUCKETS, my_hash_fn, NULL, my_cmp_fn); \endcode
where
A container knows little or nothing about the objects it stores, other than the fact that they have been created by ao2_alloc(). All knowledge of the (user-defined) internals of the objects is left to the (user-supplied) functions passed as arguments to ao2_container_alloc_hash().
If we want to insert an object in a container, we should initialize its fields – especially, those used by my_hash_fn() – to compute the bucket to use. Once done, we can link an object to a container with
ao2_link(c, o);
The function returns NULL in case of errors (and the object is not inserted in the container). Other values mean success (we are not supposed to use the value as a pointer to anything). Linking an object to a container increases its refcount by 1 automatically.