2070 lines
78 KiB
C
2070 lines
78 KiB
C
/*
|
|
* astobj2 - replacement containers for asterisk data structures.
|
|
*
|
|
* Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
|
|
*
|
|
* See http://www.asterisk.org for more information about
|
|
* the Asterisk project. Please do not directly contact
|
|
* any of the maintainers of this project for assistance;
|
|
* the project provides a web site, mailing lists and IRC
|
|
* channels for your use.
|
|
*
|
|
* This program is free software, distributed under the terms of
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
* at the top of the source tree.
|
|
*/
|
|
|
|
#ifndef _ASTERISK_ASTOBJ2_H
|
|
#define _ASTERISK_ASTOBJ2_H
|
|
|
|
#include "asterisk/compat.h"
|
|
#include "asterisk/lock.h"
|
|
#include "asterisk/linkedlists.h"
|
|
#include "asterisk/inline_api.h"
|
|
|
|
/*! \file
|
|
* \ref AstObj2
|
|
*
|
|
* \page AstObj2 Object Model implementing objects and containers.
|
|
|
|
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.
|
|
|
|
\section AstObj2_UsageObjects USAGE - OBJECTS
|
|
|
|
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():
|
|
|
|
- the object has a refcount = 1;
|
|
- the memory for the object is allocated dynamically and zeroed;
|
|
- we cannot realloc() the object itself;
|
|
- 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.
|
|
|
|
|
|
\section AstObj2_UsageContainers USAGE - CONTAINERS
|
|
|
|
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
|
|
|
|
- MAX_BUCKETS is the number of buckets in the hash table,
|
|
- my_hash_fn() is the (user-supplied) function that returns a
|
|
hash key for the object (further reduced modulo MAX_BUCKETS
|
|
by the container's code);
|
|
- my_cmp_fn() is the default comparison function used when doing
|
|
searches on the container,
|
|
|
|
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.
|
|
|
|
\note While an object o is in a container, we expect that
|
|
my_hash_fn(o) will always return the same value. The function
|
|
does not lock the object to be computed, so modifications of
|
|
those fields that affect the computation of the hash should
|
|
be done by extracting the object from the container, and
|
|
re-inserting it after the change (this is not terribly expensive).
|
|
|
|
\note A container with a single buckets is effectively a linked
|
|
list. However there is no ordering among elements.
|
|
|
|
- \ref AstObj2_Containers
|
|
- \ref astobj2.h All documentation for functions and data structures
|
|
|
|
*/
|
|
|
|
/*
|
|
\note DEBUGGING REF COUNTS BIBLE:
|
|
An interface to help debug refcounting is provided
|
|
in this package. It is dependent on the refdebug being enabled in
|
|
asterisk.conf.
|
|
|
|
Each of the reference manipulations will generate one line of output in the refs
|
|
log file. These lines look like this:
|
|
...
|
|
0x8756f00,+1,1234,chan_sip.c,22240,load_module,**constructor**,allocate users
|
|
0x86e3408,+1,1234,chan_sip.c,22241,load_module,**constructor**,allocate peers
|
|
0x86dd380,+1,1234,chan_sip.c,22242,load_module,**constructor**,allocate peers_by_ip
|
|
0x822d020,+1,1234,chan_sip.c,22243,load_module,**constructor**,allocate dialogs
|
|
0x8930fd8,+1,1234,chan_sip.c,20025,build_peer,**constructor**,allocate a peer struct
|
|
0x8930fd8,+1,1234,chan_sip.c,21467,reload_config,1,link peer into peer table
|
|
0x8930fd8,-1,1234,chan_sip.c,2370,unref_peer,2,unref_peer: from reload_config
|
|
0x89318b0,1,5678,chan_sip.c,20025,build_peer,**constructor**,allocate a peer struct
|
|
0x89318b0,+1,5678,chan_sip.c,21467,reload_config,1,link peer into peer table
|
|
0x89318b0,-1,1234,chan_sip.c,2370,unref_peer,2,unref_peer: from reload_config
|
|
0x8930218,+1,1234,chan_sip.c,20025,build_peer,**constructor**,allocate a peer struct
|
|
0x8930218,+1,1234,chan_sip.c,21539,reload_config,1,link peer into peers table
|
|
0x868c040,-1,1234,chan_sip.c,2424,dialog_unlink_all,2,unset the relatedpeer->call field in tandem with relatedpeer field itself
|
|
0x868c040,-1,1234,chan_sip.c,2443,dialog_unlink_all,1,Let's unbump the count in the unlink so the poor pvt can disappear if it is time
|
|
0x868c040,-1,1234,chan_sip.c,2443,dialog_unlink_all,**destructor**,Let's unbump the count in the unlink so the poor pvt can disappear if it is time
|
|
0x8cc07e8,-1,1234,chan_sip.c,2370,unref_peer,3,unsetting a dialog relatedpeer field in sip_destroy
|
|
0x8cc07e8,+1,1234,chan_sip.c,3876,find_peer,2,ao2_find in peers table
|
|
0x8cc07e8,-1,1234,chan_sip.c,2370,unref_peer,3,unref_peer, from sip_devicestate, release ref from find_peer
|
|
...
|
|
|
|
This uses a comma delineated format. The columns in the format are as
|
|
follows:
|
|
- The first column is the object address.
|
|
- The second column reflects how the operation affected the ref count
|
|
for that object. A change in the ref count is reflected either as
|
|
an increment (+) or decrement (-), as well as the amount it changed
|
|
by.
|
|
- The third column is the ID of the thread that modified the reference
|
|
count.
|
|
- The fourth column is the source file that the change in reference was
|
|
issued from.
|
|
- The fifth column is the line number of the source file that the ref
|
|
change was issued from.
|
|
- The sixth column is the name of the function that the ref change was
|
|
issued from.
|
|
- The seventh column indicates either (a) construction of the object via
|
|
the special tag **constructor**; (b) destruction of the object via
|
|
the special tag **destructor**; (c) the previous reference count
|
|
prior to this reference change.
|
|
- The eighth column is a special tag added by the developer to provide
|
|
context for the ref change. Note that any subsequent columns are
|
|
considered to be part of this tag.
|
|
|
|
Sometimes you have some helper functions to do object create/ref/unref
|
|
operations. Using these normally hides the place where these
|
|
functions were called. To get the location where these functions
|
|
were called to appear in refs log, you can do this sort of thing:
|
|
|
|
#define my_t_alloc(data,tag) my_alloc_debug((data), tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define my_alloc(data) my_t_alloc((data), NULL)
|
|
|
|
static struct mydata *my_alloc_debug(void *data,
|
|
const char *tag, const char *file, int line, const char *func)
|
|
{
|
|
struct mydata *p;
|
|
|
|
p = __ao2_alloc(sizeof(*p), NULL, AO2_ALLOC_OPT_LOCK_MUTEX, tag, file, line, func);
|
|
if (p) {
|
|
p->data = data;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
To find out why objects are not destroyed (a common bug), you can
|
|
enable refdebug in asterisk.conf. Run asterisk, exit with "core stop gracefully".
|
|
This should result in every object being destroyed.
|
|
|
|
Then, you can "sort -k 1 {AST_LOG_DIR}/refs > x1" to get a sorted list of
|
|
all the objects, or you can use "contrib/script/refcounter.py" to scan
|
|
the file for you and output any problems it finds.
|
|
|
|
The above may seem astronomically more work than it is worth to debug
|
|
reference counts, which may be true in "simple" situations, but for
|
|
more complex situations, it is easily worth 100 times this effort to
|
|
help find problems.
|
|
|
|
To debug, pair all calls so that each call that increments the
|
|
refcount is paired with a corresponding call that decrements the
|
|
count for the same reason. Hopefully, you will be left with one
|
|
or more unpaired calls. This is where you start your search!
|
|
|
|
For instance, here is an example of this for a dialog object in
|
|
chan_sip, that was not getting destroyed, after I moved the lines around
|
|
to pair operations:
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,5733,sip_alloc,**constructor**,(allocate a dialog(pvt) struct)
|
|
0x83787a0,-1,1234,chan_sip.c,19173,sip_poke_peer,4,(unref dialog at end of sip_poke_peer, obtained from sip_alloc, just before it goes out of scope)
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,5854,sip_alloc,1,(link pvt into dialogs table)
|
|
0x83787a0,-1,1234,chan_sip.c,19150,sip_poke_peer,3,(About to change the callid -- remove the old name)
|
|
0x83787a0,+1,1234,chan_sip.c,19152,sip_poke_peer,2,(Linking in under new name)
|
|
0x83787a0,-1,1234,chan_sip.c,2399,dialog_unlink_all,5,(unlinking dialog via ao2_unlink)
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,19130,sip_poke_peer,2,(copy sip alloc from p to peer->call)
|
|
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,2996,__sip_reliable_xmit,3,(__sip_reliable_xmit: setting pkt->owner)
|
|
0x83787a0,-1,1234,chan_sip.c,2425,dialog_unlink_all,4,(remove all current packets in this dialog, and the pointer to the dialog too as part of __sip_destroy)
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,22356,unload_module,4,(iterate thru dialogs)
|
|
0x83787a0,-1,1234,chan_sip.c,22359,unload_module,5,(toss dialog ptr from iterator_next)
|
|
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,22373,unload_module,3,(iterate thru dialogs)
|
|
0x83787a0,-1,1234,chan_sip.c,22375,unload_module,2,(throw away iterator result)
|
|
|
|
0x83787a0,+1,1234,chan_sip.c,2397,dialog_unlink_all,4,(Let's bump the count in the unlink so it doesn't accidentally become dead before we are done)
|
|
0x83787a0,-1,1234,chan_sip.c,2436,dialog_unlink_all,3,(Let's unbump the count in the unlink so the poor pvt can disappear if it is time)
|
|
|
|
As you can see, only one unbalanced operation is in the list, a ref count increment when
|
|
the peer->call was set, but no corresponding decrement was made...
|
|
|
|
Hopefully this helps you narrow your search and find those bugs.
|
|
|
|
THE ART OF REFERENCE COUNTING
|
|
(by Steve Murphy)
|
|
SOME TIPS for complicated code, and ref counting:
|
|
|
|
1. Theoretically, passing a refcounted object pointer into a function
|
|
call is an act of copying the reference, and could be refcounted.
|
|
But, upon examination, this sort of refcounting will explode the amount
|
|
of code you have to enter, and for no tangible benefit, beyond
|
|
creating more possible failure points/bugs. It will even
|
|
complicate your code and make debugging harder, slow down your program
|
|
doing useless increments and decrements of the ref counts.
|
|
|
|
2. It is better to track places where a ref counted pointer
|
|
is copied into a structure or stored. Make sure to decrement the refcount
|
|
of any previous pointer that might have been there, if setting
|
|
this field might erase a previous pointer. ao2_find and iterate_next
|
|
internally increment the ref count when they return a pointer, so
|
|
you need to decrement the count before the pointer goes out of scope.
|
|
|
|
3. Any time you decrement a ref count, it may be possible that the
|
|
object will be destroyed (freed) immediately by that call. If you
|
|
are destroying a series of fields in a refcounted object, and
|
|
any of the unref calls might possibly result in immediate destruction,
|
|
you can first increment the count to prevent such behavior, then
|
|
after the last test, decrement the pointer to allow the object
|
|
to be destroyed, if the refcount would be zero.
|
|
|
|
Example:
|
|
|
|
dialog_ref(dialog, "Let's bump the count in the unlink so it doesn't accidentally become dead before we are done");
|
|
|
|
ao2_t_unlink(dialogs, dialog, "unlinking dialog via ao2_unlink");
|
|
|
|
*//* Unlink us from the owner (channel) if we have one *//*
|
|
if (dialog->owner) {
|
|
if (lockowner) {
|
|
ast_channel_lock(dialog->owner);
|
|
}
|
|
ast_debug(1, "Detaching from channel %s\n", dialog->owner->name);
|
|
dialog->owner->tech_pvt = dialog_unref(dialog->owner->tech_pvt, "resetting channel dialog ptr in unlink_all");
|
|
if (lockowner) {
|
|
ast_channel_unlock(dialog->owner);
|
|
}
|
|
}
|
|
if (dialog->registry) {
|
|
if (dialog->registry->call == dialog) {
|
|
dialog->registry->call = dialog_unref(dialog->registry->call, "nulling out the registry's call dialog field in unlink_all");
|
|
}
|
|
dialog->registry = registry_unref(dialog->registry, "delete dialog->registry");
|
|
}
|
|
...
|
|
dialog_unref(dialog, "Let's unbump the count in the unlink so the poor pvt can disappear if it is time");
|
|
|
|
In the above code, the ao2_t_unlink could end up destroying the dialog
|
|
object; if this happens, then the subsequent usages of the dialog
|
|
pointer could result in a core dump. So, we 'bump' the
|
|
count upwards before beginning, and then decrementing the count when
|
|
we are finished. This is analogous to 'locking' or 'protecting' operations
|
|
for a short while.
|
|
|
|
4. One of the most insidious problems I've run into when converting
|
|
code to do ref counted automatic destruction, is in the destruction
|
|
routines. Where a "destroy" routine had previously been called to
|
|
get rid of an object in non-refcounted code, the new regime demands
|
|
that you tear that "destroy" routine into two pieces, one that will
|
|
tear down the links and 'unref' them, and the other to actually free
|
|
and reset fields. A destroy routine that does any reference deletion
|
|
for its own object, will never be called. Another insidious problem
|
|
occurs in mutually referenced structures. As an example, a dialog contains
|
|
a pointer to a peer, and a peer contains a pointer to a dialog. Watch
|
|
out that the destruction of one doesn't depend on the destruction of the
|
|
other, as in this case a dependency loop will result in neither being
|
|
destroyed!
|
|
|
|
Given the above, you should be ready to do a good job!
|
|
|
|
murf
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
* \brief Typedef for an object destructor.
|
|
*
|
|
* \param vdoomed Object to destroy.
|
|
*
|
|
* \details
|
|
* This is called just before freeing the memory for the object.
|
|
* It is passed a pointer to the user-defined data of the
|
|
* object.
|
|
*/
|
|
typedef void (*ao2_destructor_fn)(void *vdoomed);
|
|
|
|
/*! \brief Options available when allocating an ao2 object. */
|
|
enum ao2_alloc_opts {
|
|
/*! The ao2 object has a recursive mutex lock associated with it. */
|
|
AO2_ALLOC_OPT_LOCK_MUTEX = (0 << 0),
|
|
/*! The ao2 object has a non-recursive read/write lock associated with it. */
|
|
AO2_ALLOC_OPT_LOCK_RWLOCK = (1 << 0),
|
|
/*! The ao2 object has no lock associated with it. */
|
|
AO2_ALLOC_OPT_LOCK_NOLOCK = (2 << 0),
|
|
/*! The ao2 object locking option field mask. */
|
|
AO2_ALLOC_OPT_LOCK_MASK = (3 << 0),
|
|
/*!
|
|
* \internal The ao2 object uses a separate object for locking.
|
|
*
|
|
* \note This option is used internally by ao2_alloc_with_lockobj and
|
|
* should never be passed directly to ao2_alloc.
|
|
*/
|
|
AO2_ALLOC_OPT_LOCK_OBJ = AO2_ALLOC_OPT_LOCK_MASK,
|
|
/*! The ao2 object will not record any REF_DEBUG entries */
|
|
AO2_ALLOC_OPT_NO_REF_DEBUG = (1 << 2),
|
|
};
|
|
|
|
/*!
|
|
* \brief Allocate and initialize an object.
|
|
*
|
|
* \param data_size The sizeof() of the user-defined structure.
|
|
* \param destructor_fn The destructor function (can be NULL)
|
|
* \param options The ao2 object options (See enum ao2_alloc_opts)
|
|
* \param debug_msg An ao2 object debug tracing message.
|
|
* \return A pointer to user-data.
|
|
*
|
|
* \details
|
|
* Allocates a struct astobj2 with sufficient space for the
|
|
* user-defined structure.
|
|
* \note
|
|
* - storage is zeroed; XXX maybe we want a flag to enable/disable this.
|
|
* - the refcount of the object just created is 1
|
|
* - the returned pointer cannot be free()'d or realloc()'ed;
|
|
* rather, we just call ao2_ref(o, -1);
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg) \
|
|
__ao2_alloc((data_size), (destructor_fn), (options), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_alloc_options(data_size, destructor_fn, options) \
|
|
__ao2_alloc((data_size), (destructor_fn), (options), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
|
|
__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_alloc(data_size, destructor_fn) \
|
|
__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*! @} */
|
|
|
|
/*!
|
|
* \since 14.1.0
|
|
* \brief Allocate and initialize an object with separate locking.
|
|
*
|
|
* \param data_size The sizeof() of the user-defined structure.
|
|
* \param destructor_fn The destructor function (can be NULL)
|
|
* \param lockobj A separate ao2 object that will provide locking.
|
|
* \param tag An ao2 object debug tracing message.
|
|
* \return A pointer to user-data.
|
|
*
|
|
* \see \ref ao2_alloc for additional details.
|
|
*
|
|
* \note lockobj must be a valid AO2 object.
|
|
*/
|
|
#define ao2_alloc_with_lockobj(data_size, destructor_fn, lockobj, tag) \
|
|
__ao2_alloc_with_lockobj((data_size), (destructor_fn), (lockobj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*! \brief
|
|
* Reference/unreference an object and return the old refcount.
|
|
*
|
|
* \param o A pointer to the object
|
|
* \param delta Value to add to the reference counter.
|
|
* \return The value of the reference counter before the operation.
|
|
*
|
|
* Increase/decrease the reference counter according
|
|
* the value of delta.
|
|
*
|
|
* If the refcount goes to zero, the object is destroyed.
|
|
*
|
|
* \note The object must not be locked by the caller of this function, as
|
|
* it is invalid to try to unlock it after releasing the reference.
|
|
*
|
|
* \note if we know the pointer to an object, it is because we
|
|
* have a reference count to it, so the only case when the object
|
|
* can go away is when we release our reference, and it is
|
|
* the last one in existence.
|
|
*
|
|
* @{
|
|
*/
|
|
#define ao2_ref(o,delta) __ao2_ref((o), (delta), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_t_ref(o,delta,tag) __ao2_ref((o), (delta), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
/*!
|
|
* \brief Retrieve the ao2 options used to create the object.
|
|
* \param obj pointer to the (user-defined part) of an object.
|
|
* \return options from enum ao2_alloc_opts.
|
|
*/
|
|
unsigned int ao2_options_get(void *obj);
|
|
|
|
/*!
|
|
* \since 12
|
|
* \brief Bump refcount on an AO2 object by one, returning the object.
|
|
*
|
|
* This is useful for inlining a ref bump, and you don't care about the ref
|
|
* count. Also \c NULL safe, for even more convenience.
|
|
*
|
|
* \param obj AO2 object to bump the refcount on.
|
|
*
|
|
* \return The given \a obj pointer.
|
|
*/
|
|
#define ao2_bump(obj) \
|
|
ao2_t_bump((obj), NULL)
|
|
|
|
#define ao2_t_bump(obj, tag) \
|
|
({ \
|
|
typeof(obj) __obj_ ## __LINE__ = (obj); \
|
|
if (__obj_ ## __LINE__) { \
|
|
ao2_t_ref(__obj_ ## __LINE__, +1, (tag)); \
|
|
} \
|
|
__obj_ ## __LINE__; \
|
|
})
|
|
|
|
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*!
|
|
* \since 12.4.0
|
|
* \brief Replace one object reference with another cleaning up the original.
|
|
*
|
|
* \param dst Pointer to the object that will be cleaned up.
|
|
* \param src Pointer to the object replacing it.
|
|
*/
|
|
#define ao2_replace(dst, src) \
|
|
ao2_t_replace((dst), (src), NULL)
|
|
|
|
#define ao2_t_replace(dst, src, tag) \
|
|
{\
|
|
typeof(dst) *__dst_ ## __LINE__ = &dst; \
|
|
typeof(src) __src_ ## __LINE__ = src; \
|
|
if (__src_ ## __LINE__ != *__dst_ ## __LINE__) { \
|
|
if (__src_ ## __LINE__) {\
|
|
ao2_t_ref(__src_ ## __LINE__, +1, (tag)); \
|
|
} \
|
|
if (*__dst_ ## __LINE__) {\
|
|
ao2_t_ref(*__dst_ ## __LINE__, -1, (tag)); \
|
|
} \
|
|
*__dst_ ## __LINE__ = __src_ ## __LINE__; \
|
|
} \
|
|
}
|
|
|
|
/*! @} */
|
|
|
|
/*! \brief ao2_weakproxy
|
|
*
|
|
* @{
|
|
*/
|
|
struct ao2_weakproxy_notification;
|
|
typedef void (*ao2_weakproxy_notification_cb)(void *weakproxy, void *data);
|
|
|
|
/*! \brief This struct should be opaque, but it's size is needed. */
|
|
struct ao2_weakproxy {
|
|
AST_LIST_HEAD_NOLOCK(, ao2_weakproxy_notification) destroyed_cb;
|
|
};
|
|
|
|
/*! \brief Macro which must be used at the beginning of weakproxy capable objects.
|
|
*
|
|
* \note The primary purpose of user defined fields on weakproxy objects is to hold
|
|
* immutable container keys for the real object.
|
|
*/
|
|
#define AO2_WEAKPROXY() struct ao2_weakproxy __weakproxy##__LINE__
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Allocate an ao2_weakproxy object
|
|
*
|
|
* \param data_size The sizeof() of the user-defined structure.
|
|
* \param destructor_fn The destructor function (can be NULL)
|
|
*
|
|
* \note "struct ao2_weakproxy" must be the first field of any object.
|
|
* This can be done by using AO2_WEAKPROXY to declare your structure.
|
|
*/
|
|
#define ao2_weakproxy_alloc(data_size, destructor_fn) \
|
|
__ao2_weakproxy_alloc(data_size, destructor_fn, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_weakproxy_alloc(data_size, destructor_fn, tag) \
|
|
__ao2_weakproxy_alloc(data_size, destructor_fn, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Associate weakproxy with obj.
|
|
*
|
|
* \param weakproxy An object created by ao2_weakproxy_alloc.
|
|
* \param obj An ao2 object not created by ao2_weakproxy_alloc.
|
|
* \param flags OBJ_NOLOCK to avoid locking weakproxy.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval -1 Failure
|
|
*
|
|
* \note obj must be newly created, this procedure is not thread safe
|
|
* if any other code can reach obj before this procedure ends.
|
|
*
|
|
* \note weakproxy may be previously existing, but must not currently
|
|
* have an object set.
|
|
*
|
|
* \note The only way to unset an object is for it to be destroyed.
|
|
* Any call to this function while an object is already set will fail.
|
|
*/
|
|
#define ao2_weakproxy_set_object(weakproxy, obj, flags) \
|
|
__ao2_weakproxy_set_object(weakproxy, obj, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_weakproxy_set_object(weakproxy, obj, flags, tag) \
|
|
__ao2_weakproxy_set_object(weakproxy, obj, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Run ao2_t_ref on the object associated with weakproxy.
|
|
*
|
|
* \param weakproxy The weakproxy to read from.
|
|
* \param delta Value to add to the reference counter.
|
|
* \param flags OBJ_NOLOCK to avoid locking weakproxy.
|
|
*
|
|
* \retval -2 weakproxy is not a valid ao2_weakproxy.
|
|
* \retval -1 weakproxy has no associated object.
|
|
*
|
|
* \return The value of the reference counter before the operation.
|
|
*/
|
|
#define ao2_weakproxy_ref_object(weakproxy, delta, flags) \
|
|
ao2_t_weakproxy_ref_object(weakproxy, delta, flags, NULL)
|
|
|
|
#define ao2_t_weakproxy_ref_object(weakproxy, delta, flags, tag) \
|
|
__ao2_weakproxy_ref_object(weakproxy, delta, flags, \
|
|
tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Get the object associated with weakproxy.
|
|
*
|
|
* \param weakproxy The weakproxy to read from.
|
|
* \param flags OBJ_NOLOCK to avoid locking weakproxy.
|
|
*
|
|
* \return A reference to the object previously set by ao2_weakproxy_set_object.
|
|
* \retval NULL Either no object was set or the previously set object has been freed.
|
|
*/
|
|
#define ao2_weakproxy_get_object(weakproxy, flags) \
|
|
__ao2_weakproxy_get_object(weakproxy, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_weakproxy_get_object(weakproxy, flags, tag) \
|
|
__ao2_weakproxy_get_object(weakproxy, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Request notification when weakproxy points to NULL.
|
|
*
|
|
* \param weakproxy The weak object
|
|
* \param cb Procedure to call when no real object is associated
|
|
* \param data Passed to cb
|
|
* \param flags OBJ_NOLOCK to avoid locking weakproxy.
|
|
*
|
|
* \retval 0 Success
|
|
* \retval -1 Failure
|
|
*
|
|
* \note Callbacks are run in the reverse order of subscriptions.
|
|
*
|
|
* \note This procedure will allow the same cb / data pair to be added to
|
|
* the same weakproxy multiple times.
|
|
*
|
|
* \note It is the caller's responsibility to ensure that *data is valid
|
|
* until after cb() is run or ao2_weakproxy_unsubscribe is called.
|
|
*
|
|
* \note If the weakproxy currently points to NULL the callback will be run immediately,
|
|
* without being added to the subscriber list.
|
|
*/
|
|
int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags);
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Remove notification of real object destruction.
|
|
*
|
|
* \param weakproxy The weak object
|
|
* \param cb Callback to remove from destroy notification list
|
|
* \param data Data pointer to match
|
|
* \param flags OBJ_NOLOCK to avoid locking weakproxy.
|
|
* OBJ_MULTIPLE to remove all copies of the same cb / data pair.
|
|
*
|
|
* \return The number of subscriptions removed.
|
|
* \retval 0 cb / data pair not found, nothing removed.
|
|
* \retval -1 Failure due to invalid parameters.
|
|
*
|
|
* \note Unless flags includes OBJ_MULTIPLE, this will only remove a single copy
|
|
* of the cb / data pair. If it was subscribed multiple times it must be
|
|
* unsubscribed as many times. The OBJ_MULTIPLE flag can be used to remove
|
|
* matching subscriptions.
|
|
*
|
|
* \note When it's time to run callbacks they are copied to a temporary list so the
|
|
* weakproxy can be unlocked before running. That means it's possible for
|
|
* this function to find nothing before the callback is run in another thread.
|
|
*/
|
|
int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags);
|
|
|
|
/*!
|
|
* \since 14.0.0
|
|
* \brief Get the weakproxy attached to obj
|
|
*
|
|
* \param obj The object to retrieve a weakproxy from
|
|
*
|
|
* \return The weakproxy object
|
|
*/
|
|
#define ao2_get_weakproxy(obj) \
|
|
__ao2_get_weakproxy(obj, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_get_weakproxy(obj, tag) \
|
|
__ao2_get_weakproxy(obj, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_get_weakproxy(void *obj,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
/*! @} */
|
|
|
|
|
|
/*! \brief Which lock to request. */
|
|
enum ao2_lock_req {
|
|
/*! Request the mutex lock be acquired. */
|
|
AO2_LOCK_REQ_MUTEX,
|
|
/*! Request the read lock be acquired. */
|
|
AO2_LOCK_REQ_RDLOCK,
|
|
/*! Request the write lock be acquired. */
|
|
AO2_LOCK_REQ_WRLOCK,
|
|
};
|
|
|
|
/*! \brief
|
|
* Lock an object.
|
|
*
|
|
* \param a A pointer to the object we want to lock.
|
|
* \param lock_how, file, func, line, var
|
|
* \return 0 on success, other values on error.
|
|
*/
|
|
int __ao2_lock(void *a, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var);
|
|
#define ao2_lock(a) __ao2_lock(a, AO2_LOCK_REQ_MUTEX, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
#define ao2_rdlock(a) __ao2_lock(a, AO2_LOCK_REQ_RDLOCK, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
#define ao2_wrlock(a) __ao2_lock(a, AO2_LOCK_REQ_WRLOCK, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
|
|
/*! \brief
|
|
* Unlock an object.
|
|
*
|
|
* \param a A pointer to the object we want unlock.
|
|
* \param file, func, line, var
|
|
* \return 0 on success, other values on error.
|
|
*/
|
|
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
|
|
#define ao2_unlock(a) __ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
|
|
/*! \brief
|
|
* Try locking-- (don't block if fail)
|
|
*
|
|
* \param a A pointer to the object we want to lock.
|
|
* \param lock_how, file, func, line, var
|
|
* \return 0 on success, other values on error.
|
|
*/
|
|
int __ao2_trylock(void *a, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var);
|
|
#define ao2_trylock(a) __ao2_trylock(a, AO2_LOCK_REQ_MUTEX, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
#define ao2_tryrdlock(a) __ao2_trylock(a, AO2_LOCK_REQ_RDLOCK, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
#define ao2_trywrlock(a) __ao2_trylock(a, AO2_LOCK_REQ_WRLOCK, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
|
|
|
|
/*!
|
|
* \brief Return the mutex lock address of an object
|
|
*
|
|
* \param[in] obj A pointer to the object we want.
|
|
* \return the address of the mutex lock, else NULL.
|
|
*
|
|
* This function comes in handy mainly for debugging locking
|
|
* situations, where the locking trace code reports the
|
|
* lock address, this allows you to correlate against
|
|
* object address, to match objects to reported locks.
|
|
*
|
|
* \warning AO2 lock objects do not include tracking fields when
|
|
* DEBUG_THREADS is not enabled.
|
|
*
|
|
* \since 1.6.1
|
|
*/
|
|
void *ao2_object_get_lockaddr(void *obj);
|
|
|
|
|
|
/*!
|
|
* \brief Increment reference count on an object and lock it
|
|
* \since 13.9.0
|
|
*
|
|
* \param[in] obj A pointer to the ao2 object
|
|
* \retval 0 The object is not an ao2 object or wasn't locked successfully
|
|
* \retval 1 The object's reference count was incremented and was locked
|
|
*/
|
|
AST_INLINE_API(
|
|
int ao2_ref_and_lock(void *obj),
|
|
{
|
|
ao2_ref(obj, +1);
|
|
if (ao2_lock(obj)) {
|
|
ao2_ref(obj, -1);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
)
|
|
|
|
/*!
|
|
* \brief Unlock an object and decrement its reference count
|
|
* \since 13.9.0
|
|
*
|
|
* \param[in] obj A pointer to the ao2 object
|
|
* \retval 0 The object is not an ao2 object or wasn't unlocked successfully
|
|
* \retval 1 The object was unlocked and it's reference count was decremented
|
|
*/
|
|
AST_INLINE_API(
|
|
int ao2_unlock_and_unref(void *obj),
|
|
{
|
|
if (ao2_unlock(obj)) {
|
|
return 0;
|
|
}
|
|
ao2_ref(obj, -1);
|
|
|
|
return 1;
|
|
}
|
|
)
|
|
|
|
/*! Global ao2 object holder structure. */
|
|
struct ao2_global_obj {
|
|
/*! Access lock to the held ao2 object. */
|
|
ast_rwlock_t lock;
|
|
/*! Global ao2 object. */
|
|
void *obj;
|
|
};
|
|
|
|
/*!
|
|
* \brief Define a global object holder to be used to hold an ao2 object, statically initialized.
|
|
* \since 11.0
|
|
*
|
|
* \param name This will be the name of the object holder.
|
|
*
|
|
* \details
|
|
* This macro creates a global object holder that can be used to
|
|
* hold an ao2 object accessible using the API. The structure is
|
|
* allocated and initialized to be empty.
|
|
*
|
|
* Example usage:
|
|
* \code
|
|
* static AO2_GLOBAL_OBJ_STATIC(global_cfg);
|
|
* \endcode
|
|
*
|
|
* This defines global_cfg, intended to hold an ao2 object
|
|
* accessible using an API.
|
|
*/
|
|
#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
|
|
#define AO2_GLOBAL_OBJ_STATIC(name) \
|
|
struct ao2_global_obj name; \
|
|
static void __attribute__((constructor)) __init_##name(void) \
|
|
{ \
|
|
ast_rwlock_init(&name.lock); \
|
|
name.obj = NULL; \
|
|
} \
|
|
static void __attribute__((destructor)) __fini_##name(void) \
|
|
{ \
|
|
if (name.obj) { \
|
|
ao2_ref(name.obj, -1); \
|
|
name.obj = NULL; \
|
|
} \
|
|
ast_rwlock_destroy(&name.lock); \
|
|
} \
|
|
struct __dummy_##name
|
|
#else
|
|
#define AO2_GLOBAL_OBJ_STATIC(name) \
|
|
struct ao2_global_obj name = { \
|
|
.lock = AST_RWLOCK_INIT_VALUE, \
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
* \brief Release the ao2 object held in the global holder.
|
|
* \since 11.0
|
|
*
|
|
* \param holder Global ao2 object holder.
|
|
*/
|
|
#define ao2_global_obj_release(holder) \
|
|
__ao2_global_obj_replace_unref(&holder, NULL, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
#define ao2_t_global_obj_release(holder, tag) \
|
|
__ao2_global_obj_replace_unref(&holder, NULL, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
/*!
|
|
* \brief Replace an ao2 object in the global holder.
|
|
* \since 11.0
|
|
*
|
|
* \param holder Global ao2 object holder.
|
|
* \param obj Object to put into the holder. Can be NULL.
|
|
*
|
|
* \note This function automatically increases the reference
|
|
* count to account for the reference that the global holder now
|
|
* holds to the object.
|
|
*
|
|
* \return Reference to previous global ao2 object stored.
|
|
* \retval NULL if no object available.
|
|
*/
|
|
#define ao2_global_obj_replace(holder, obj) \
|
|
__ao2_global_obj_replace(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
#define ao2_t_global_obj_replace(holder, obj, tag) \
|
|
__ao2_global_obj_replace(&holder, (obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Replace an ao2 object in the global holder, throwing away any old object.
|
|
* \since 11.0
|
|
*
|
|
* \param holder Global ao2 object holder.
|
|
* \param obj Object to put into the holder. Can be NULL.
|
|
*
|
|
* \note This function automatically increases the reference
|
|
* count to account for the reference that the global holder now
|
|
* holds to the object. It also decreases the reference count
|
|
* of any object being replaced.
|
|
*
|
|
* \retval 0 The global object was previously empty
|
|
* \retval 1 The global object was not previously empty
|
|
*/
|
|
#define ao2_global_obj_replace_unref(holder, obj) \
|
|
__ao2_global_obj_replace_unref(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
#define ao2_t_global_obj_replace_unref(holder, obj, tag) \
|
|
__ao2_global_obj_replace_unref(&holder, (obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name);
|
|
|
|
/*!
|
|
* \brief Get a reference to the object stored in the global holder.
|
|
* \since 11.0
|
|
*
|
|
* \param holder Global ao2 object holder.
|
|
*
|
|
* \return Reference to current ao2 object stored in the holder.
|
|
* \retval NULL if no object available.
|
|
*/
|
|
#define ao2_global_obj_ref(holder) \
|
|
__ao2_global_obj_ref(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
#define ao2_t_global_obj_ref(holder, tag) \
|
|
__ao2_global_obj_ref(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
|
|
|
|
void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
|
|
|
|
|
|
/*!
|
|
\page AstObj2_Containers AstObj2 Containers
|
|
|
|
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:
|
|
|
|
- \b 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.
|
|
|
|
- \b 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.
|
|
|
|
- \b iterate on a container
|
|
this is done with the following sequence
|
|
|
|
\code
|
|
|
|
struct ao2_container *c = ... // our container
|
|
struct ao2_iterator i;
|
|
void *o;
|
|
|
|
i = ao2_iterator_init(c, flags);
|
|
|
|
while ((o = ao2_iterator_next(&i))) {
|
|
... do something on o ...
|
|
ao2_ref(o, -1);
|
|
}
|
|
|
|
ao2_iterator_destroy(&i);
|
|
\endcode
|
|
|
|
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.
|
|
|
|
- \ref AstObj2
|
|
- \ref astobj2.h
|
|
*/
|
|
|
|
/*! \brief
|
|
* A callback function will return a combination of CMP_MATCH and CMP_STOP.
|
|
* The latter will terminate the search in a container.
|
|
*/
|
|
enum _cb_results {
|
|
CMP_MATCH = 0x1, /*!< the object matches the request */
|
|
CMP_STOP = 0x2, /*!< stop the search now */
|
|
};
|
|
|
|
/*!
|
|
* \brief Flags passed to ao2_callback_fn(), ao2_hash_fn(), and ao2_sort_fn() to modify behaviour.
|
|
*/
|
|
enum search_flags {
|
|
/*!
|
|
* Unlink the object for which the callback function returned
|
|
* CMP_MATCH.
|
|
*/
|
|
OBJ_UNLINK = (1 << 0),
|
|
/*!
|
|
* On match, don't return the object hence do not increase its
|
|
* refcount.
|
|
*/
|
|
OBJ_NODATA = (1 << 1),
|
|
/*!
|
|
* Don't stop at the first match in ao2_callback() unless the
|
|
* result of the callback function has the CMP_STOP bit set.
|
|
*/
|
|
OBJ_MULTIPLE = (1 << 2),
|
|
/*!
|
|
* \brief Assume that the ao2_container is already locked.
|
|
*
|
|
* \note For ao2_containers that have mutexes, no locking will
|
|
* be done.
|
|
*
|
|
* \note For ao2_containers that have RWLOCKs, the lock will be
|
|
* promoted to write mode as needed. The lock will be returned
|
|
* to the original locked state.
|
|
*
|
|
* \note Only use this flag if the ao2_container is manually
|
|
* locked already.
|
|
*/
|
|
OBJ_NOLOCK = (1 << 4),
|
|
|
|
/*!
|
|
* \brief Search option field mask.
|
|
*
|
|
* \todo Eventually OBJ_SEARCH_MASK will shrink to a two bit
|
|
* field when the codebase is made to use the search field
|
|
* values as a field instead of independent bits.
|
|
*/
|
|
OBJ_SEARCH_MASK = (0x07 << 5),
|
|
/*! \brief The arg parameter has no meaning to the astobj2 code. */
|
|
OBJ_SEARCH_NONE = (0 << 5),
|
|
/*!
|
|
* \brief The arg parameter is an object of the same type.
|
|
*
|
|
* \details
|
|
* The arg parameter is an object of the same type as the one
|
|
* being searched for, so use the object's ao2_hash_fn and/or
|
|
* ao2_sort_fn functions for optimized searching.
|
|
*
|
|
* \note The supplied ao2_callback_fn is called after the
|
|
* container nodes have been filtered by the ao2_hash_fn and/or
|
|
* ao2_sort_fn functions.
|
|
*/
|
|
OBJ_SEARCH_OBJECT = (1 << 5),
|
|
/*!
|
|
* \brief The arg parameter is a search key, but is not an object.
|
|
*
|
|
* \details
|
|
* This can be used when you want to be able to pass custom data
|
|
* to the container's stored ao2_hash_fn, ao2_sort_fn, and
|
|
* ao2_find ao2_callback_fn functions that is not a full object,
|
|
* but perhaps just a string.
|
|
*
|
|
* \note The supplied ao2_callback_fn is called after the
|
|
* container nodes have been filtered by the ao2_hash_fn and/or
|
|
* ao2_sort_fn functions.
|
|
*/
|
|
OBJ_SEARCH_KEY = (2 << 5),
|
|
/*!
|
|
* \brief The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
|
|
*
|
|
* \details
|
|
* The partial key can be used by the ao2_sort_fn to guide the
|
|
* search to find a contiguous subset of a sorted container.
|
|
* For example, a sorted container holds: "A", "B", "Bert",
|
|
* "Beth", "Earnie". Doing a partial key search with "B" will
|
|
* find the sorted subset of all held objects starting with "B".
|
|
*
|
|
* \note The supplied ao2_callback_fn is called after the
|
|
* container nodes have been filtered by the ao2_sort_fn
|
|
* function.
|
|
*/
|
|
OBJ_SEARCH_PARTIAL_KEY = (4 << 5),
|
|
|
|
/*! \brief Traverse order option field mask. */
|
|
OBJ_ORDER_MASK = (0x03 << 8),
|
|
/*! \brief Traverse in ascending order (First to last container object) */
|
|
OBJ_ORDER_ASCENDING = (0 << 8),
|
|
/*! \brief Traverse in descending order (Last to first container object) */
|
|
OBJ_ORDER_DESCENDING = (1 << 8),
|
|
/*!
|
|
* \brief Traverse in pre-order (Node then children, for tree container)
|
|
*
|
|
* \note For non-tree containers, it is up to the container type
|
|
* to make the best interpretation of the order. For list and
|
|
* hash containers, this also means ascending order because a
|
|
* binary tree can degenerate into a list.
|
|
*/
|
|
OBJ_ORDER_PRE = (2 << 8),
|
|
/*!
|
|
* \brief Traverse in post-order (Children then node, for tree container)
|
|
*
|
|
* \note For non-tree containers, it is up to the container type
|
|
* to make the best interpretation of the order. For list and
|
|
* hash containers, this also means descending order because a
|
|
* binary tree can degenerate into a list.
|
|
*/
|
|
OBJ_ORDER_POST = (3 << 8),
|
|
};
|
|
|
|
/*
|
|
* Deprecated backward compatible flag names.
|
|
*
|
|
* Note: OBJ_POINTER, OBJ_KEY, and OBJ_PARTIAL_KEY are mutually
|
|
* exclusive.
|
|
*/
|
|
#define OBJ_POINTER OBJ_SEARCH_OBJECT /*!< Deprecated name */
|
|
#define OBJ_KEY OBJ_SEARCH_KEY /*!< Deprecated name */
|
|
#define OBJ_PARTIAL_KEY OBJ_SEARCH_PARTIAL_KEY /*!< Deprecated name */
|
|
|
|
/*!
|
|
* \brief Options available when allocating an ao2 container object.
|
|
*
|
|
* \note Each option is open to some interpretation by the
|
|
* container type as long as it makes sense with the option
|
|
* name.
|
|
*/
|
|
enum ao2_container_opts {
|
|
/*!
|
|
* \brief Insert objects at the beginning of the container.
|
|
* (Otherwise it is the opposite; insert at the end.)
|
|
*
|
|
* \note If an ao2_sort_fn is provided, the object is inserted
|
|
* before any objects with duplicate keys.
|
|
*
|
|
* \note Hash containers insert the object in the computed hash
|
|
* bucket in the indicated manner.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN = (1 << 0),
|
|
|
|
/*!
|
|
* \brief The ao2 container objects with duplicate keys option field mask.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_DUPS_MASK = (3 << 1),
|
|
/*!
|
|
* \brief Allow objects with duplicate keys in container.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW = (0 << 1),
|
|
/*!
|
|
* \brief Reject objects with duplicate keys in container.
|
|
*
|
|
* \note The container must be sorted. i.e. have an
|
|
* ao2_sort_fn.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT = (1 << 1),
|
|
/*!
|
|
* \brief Reject duplicate objects in container.
|
|
*
|
|
* \details Don't link the same object into the container twice.
|
|
* However, you can link a different object with the same key.
|
|
*
|
|
* \note The container must be sorted. i.e. have an
|
|
* ao2_sort_fn.
|
|
*
|
|
* \note It is assumed that the objects are located where the
|
|
* search key says they should be located.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT = (2 << 1),
|
|
/*!
|
|
* \brief Replace objects with duplicate keys in container.
|
|
*
|
|
* \details The existing duplicate object is removed and the new
|
|
* object takes the old object's place.
|
|
*
|
|
* \note The container must be sorted. i.e. have an
|
|
* ao2_sort_fn.
|
|
*/
|
|
AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE = (3 << 1),
|
|
};
|
|
|
|
/*!
|
|
* \brief Type of a generic callback function
|
|
* \param obj pointer to the (user-defined part) of an object.
|
|
* \param arg callback argument from ao2_callback()
|
|
* \param flags flags from ao2_callback()
|
|
* OBJ_SEARCH_OBJECT - if set, 'arg', is an object.
|
|
* OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
|
|
* OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
|
|
*
|
|
* The return values are a combination of enum _cb_results.
|
|
* Callback functions are used to search or manipulate objects in a container.
|
|
*/
|
|
typedef int (ao2_callback_fn)(void *obj, void *arg, int flags);
|
|
|
|
/*! \brief A common ao2_callback is one that matches by address. */
|
|
int ao2_match_by_addr(void *obj, void *arg, int flags);
|
|
|
|
/*!
|
|
* \brief Type of a generic callback function
|
|
* \param obj pointer to the (user-defined part) of an object.
|
|
* \param arg callback argument from ao2_callback()
|
|
* \param data arbitrary data from ao2_callback()
|
|
* \param flags flags from ao2_callback()
|
|
* OBJ_SEARCH_OBJECT - if set, 'arg', is an object.
|
|
* OBJ_SEARCH_KEY - if set, 'arg', is a search key item that is not an object.
|
|
* OBJ_SEARCH_PARTIAL_KEY - if set, 'arg', is a partial search key item that is not an object.
|
|
*
|
|
* The return values are a combination of enum _cb_results.
|
|
* Callback functions are used to search or manipulate objects in a container.
|
|
*/
|
|
typedef int (ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags);
|
|
|
|
/*!
|
|
* Type of a generic function to generate a hash value from an object.
|
|
*
|
|
* \param obj pointer to the (user-defined part) of an object.
|
|
* \param flags flags from ao2_callback()
|
|
* OBJ_SEARCH_OBJECT - if set, 'obj', is an object.
|
|
* OBJ_SEARCH_KEY - if set, 'obj', is a search key item that is not an object.
|
|
*
|
|
* \note This function must be idempotent.
|
|
*
|
|
* \return Computed hash value.
|
|
*/
|
|
typedef int (ao2_hash_fn)(const void *obj, int flags);
|
|
|
|
/*!
|
|
* \brief Type of generic container sort function.
|
|
*
|
|
* \param obj_left pointer to the (user-defined part) of an object.
|
|
* \param obj_right pointer to the (user-defined part) of an object.
|
|
* \param flags flags from ao2_callback()
|
|
* OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
|
|
* OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
|
|
* OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
|
|
*
|
|
* \note This function must be idempotent.
|
|
*
|
|
* \retval negtaive if obj_left < obj_right
|
|
* \retval 0 if obj_left == obj_right
|
|
* \retval positive if obj_left > obj_right
|
|
*/
|
|
typedef int (ao2_sort_fn)(const void *obj_left, const void *obj_right, int flags);
|
|
|
|
/*! \name Object Containers
|
|
* Here start declarations of containers.
|
|
*
|
|
* @{
|
|
*/
|
|
struct ao2_container;
|
|
|
|
/*!
|
|
* \brief Allocate and initialize a hash container with the desired number of buckets.
|
|
*
|
|
* \details
|
|
* We allocate space for a struct astobj_container, struct container
|
|
* and the buckets[] array.
|
|
*
|
|
* \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
|
|
* \param container_options Container behaviour options (See enum ao2_container_opts)
|
|
* \param n_buckets Number of buckets for hash
|
|
* \param hash_fn Pointer to a function computing a hash value. (NULL if everyting goes in first bucket.)
|
|
* \param sort_fn Pointer to a sort function. (NULL to not sort the buckets.)
|
|
* \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
|
|
*
|
|
* \return A pointer to a struct container.
|
|
*
|
|
* \note Destructor is set implicitly.
|
|
*/
|
|
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
|
|
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
|
|
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
|
|
unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
|
|
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Allocate and initialize a list container.
|
|
*
|
|
* \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
|
|
* \param container_options Container behaviour options (See enum ao2_container_opts)
|
|
* \param sort_fn Pointer to a sort function. (NULL if list not sorted.)
|
|
* \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
|
|
*
|
|
* \return A pointer to a struct container.
|
|
*
|
|
* \note Destructor is set implicitly.
|
|
* \note Implemented as a degenerate hash table.
|
|
*/
|
|
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
|
|
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
|
|
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
|
|
unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Allocate and initialize a red-black tree container.
|
|
*
|
|
* \param ao2_options Container ao2 object options (See enum ao2_alloc_opts)
|
|
* \param container_options Container behaviour options (See enum ao2_container_opts)
|
|
* \param sort_fn Pointer to a sort function.
|
|
* \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
|
|
*
|
|
* \return A pointer to a struct container.
|
|
*
|
|
* \note Destructor is set implicitly.
|
|
*/
|
|
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
|
|
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
|
|
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
struct ao2_container *__ao2_container_alloc_rbtree(unsigned int ao2_options, unsigned int container_options,
|
|
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*! \brief
|
|
* Returns the number of elements in a container.
|
|
*/
|
|
int ao2_container_count(struct ao2_container *c);
|
|
|
|
/*!
|
|
* \brief Copy all object references in the src container into the dest container.
|
|
* \since 11.0
|
|
*
|
|
* \param dest Container to copy src object references into.
|
|
* \param src Container to copy all object references from.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on both containers.
|
|
* Otherwise, the src container is locked first.
|
|
*
|
|
* \pre The dest container must be empty. If the duplication fails, the
|
|
* dest container will be returned empty.
|
|
*
|
|
* \note This can potentially be expensive because a malloc is
|
|
* needed for every object in the src container.
|
|
*
|
|
* \retval 0 on success.
|
|
* \retval -1 on error.
|
|
*/
|
|
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
|
|
|
|
/*!
|
|
* \brief Copy object references associated with src container weakproxies into the dest container.
|
|
*
|
|
* \param dest Container to copy src strong object references into.
|
|
* \param src Container to copy all weak object references from.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on both containers.
|
|
* Otherwise, the src container is locked first.
|
|
*
|
|
* \pre The dest container must be empty. If the duplication fails, the
|
|
* dest container will be returned empty.
|
|
*
|
|
* \note This can potentially be expensive because a malloc is
|
|
* needed for every object in the src container.
|
|
*
|
|
* \note Every object inside the container is locked by \ref ao2_weakproxy_get_object.
|
|
* Any weakproxy in \p src with no associated object is ignored.
|
|
*
|
|
* \retval 0 on success.
|
|
* \retval -1 on error.
|
|
*/
|
|
int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
|
|
|
|
/*!
|
|
* \brief Create a clone/copy of the given container.
|
|
* \since 11.0
|
|
*
|
|
* \param orig Container to copy all object references from.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on the container.
|
|
*
|
|
* \note This can potentially be expensive because a malloc is
|
|
* needed for every object in the orig container.
|
|
*
|
|
* \return Clone container on success.
|
|
* \retval NULL on error.
|
|
*/
|
|
#define ao2_container_clone(orig, flags) \
|
|
__ao2_container_clone(orig, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_container_clone(orig, flags, tag) \
|
|
__ao2_container_clone(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Print output.
|
|
* \since 12.0.0
|
|
*
|
|
* \param where User data pointer needed to determine where to put output.
|
|
* \param fmt printf type format string.
|
|
*/
|
|
typedef void (ao2_prnt_fn)(void *where, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
|
|
|
/*!
|
|
* \brief Print object key.
|
|
* \since 12.0.0
|
|
*
|
|
* \param v_obj A pointer to the object we want the key printed.
|
|
* \param where User data needed by prnt to determine where to put output.
|
|
* \param prnt Print output callback function to use.
|
|
*/
|
|
typedef void (ao2_prnt_obj_fn)(void *v_obj, void *where, ao2_prnt_fn *prnt);
|
|
|
|
/*!
|
|
* \brief Display contents of the specified container.
|
|
* \since 12.0.0
|
|
*
|
|
* \param self Container to dump.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on the container.
|
|
* \param name Container name. (NULL if anonymous)
|
|
* \param where User data needed by prnt to determine where to put output.
|
|
* \param prnt Print output callback function to use.
|
|
* \param prnt_obj Callback function to print the given object's key. (NULL if not available)
|
|
*/
|
|
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj);
|
|
|
|
/*!
|
|
* \brief Display statistics of the specified container.
|
|
* \since 12.0.0
|
|
*
|
|
* \param self Container to display statistics.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on the container.
|
|
* \param name Container name. (NULL if anonymous)
|
|
* \param where User data needed by prnt to determine where to put output.
|
|
* \param prnt Print output callback function to use.
|
|
*/
|
|
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt);
|
|
|
|
/*!
|
|
* \brief Perform an integrity check on the specified container.
|
|
* \since 12.0.0
|
|
*
|
|
* \param self Container to check integrity.
|
|
* \param flags OBJ_NOLOCK if a lock is already held on the container.
|
|
*
|
|
* \retval 0 on success.
|
|
* \retval -1 on error.
|
|
*/
|
|
int ao2_container_check(struct ao2_container *self, enum search_flags flags);
|
|
|
|
/*!
|
|
* \brief Register a container for CLI stats and integrity check.
|
|
* \since 12.0.0
|
|
*
|
|
* \param name Name to register the container under.
|
|
* \param self Container to register.
|
|
* \param prnt_obj Callback function to print the given object's key. (NULL if not available)
|
|
*
|
|
* \retval 0 on success.
|
|
* \retval -1 on error.
|
|
*/
|
|
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj);
|
|
|
|
/*!
|
|
* \brief Unregister a container for CLI stats and integrity check.
|
|
* \since 12.0.0
|
|
*
|
|
* \param name Name the container is registered under.
|
|
*/
|
|
void ao2_container_unregister(const char *name);
|
|
|
|
/*! @} */
|
|
|
|
/*! \name Object Management
|
|
* Here we have functions to manage objects.
|
|
*
|
|
* We can use the functions below on any kind of
|
|
* object defined by the user.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/*!
|
|
* \brief Add an object to a container.
|
|
*
|
|
* \param container The container to operate on.
|
|
* \param obj The object to be added.
|
|
*
|
|
* \retval 0 on errors.
|
|
* \retval 1 on success.
|
|
*
|
|
* This function inserts an object in a container according its key.
|
|
*
|
|
* \note Remember to set the key before calling this function.
|
|
*
|
|
* \note This function automatically increases the reference count to account
|
|
* for the reference that the container now holds to the object.
|
|
*/
|
|
#define ao2_link(container, obj) \
|
|
__ao2_link((container), (obj), 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_t_link(container, obj, tag) \
|
|
__ao2_link((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
/*!
|
|
* \brief Add an object to a container.
|
|
*
|
|
* \param container The container to operate on.
|
|
* \param obj The object to be added.
|
|
* \param flags search_flags to control linking the object. (OBJ_NOLOCK)
|
|
*
|
|
* \retval 0 on errors.
|
|
* \retval 1 on success.
|
|
*
|
|
* This function inserts an object in a container according its key.
|
|
*
|
|
* \note Remember to set the key before calling this function.
|
|
*
|
|
* \note This function automatically increases the reference count to account
|
|
* for the reference that the container now holds to the object.
|
|
*/
|
|
#define ao2_link_flags(container, obj, flags) \
|
|
__ao2_link((container), (obj), (flags), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_t_link_flags(container, obj, flags, tag) \
|
|
__ao2_link((container), (obj), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
int __ao2_link(struct ao2_container *c, void *obj_new, int flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*!
|
|
* \brief Remove an object from a container
|
|
*
|
|
* \param container The container to operate on.
|
|
* \param obj The object to unlink.
|
|
*
|
|
* \retval NULL always
|
|
*
|
|
* \note The object requested to be unlinked must be valid. However, if it turns
|
|
* out that it is not in the container, this function is still safe to
|
|
* be called.
|
|
*
|
|
* \note If the object gets unlinked from the container, the container's
|
|
* reference to the object will be automatically released. (The
|
|
* refcount will be decremented).
|
|
*/
|
|
#define ao2_unlink(container, obj) \
|
|
__ao2_unlink((container), (obj), 0, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_t_unlink(container, obj, tag) \
|
|
__ao2_unlink((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
/*!
|
|
* \brief Remove an object from a container
|
|
*
|
|
* \param container The container to operate on.
|
|
* \param obj The object to unlink.
|
|
* \param flags search_flags to control unlinking the object. (OBJ_NOLOCK)
|
|
*
|
|
* \retval NULL always
|
|
*
|
|
* \note The object requested to be unlinked must be valid. However, if it turns
|
|
* out that it is not in the container, this function is still safe to
|
|
* be called.
|
|
*
|
|
* \note If the object gets unlinked from the container, the container's
|
|
* reference to the object will be automatically released. (The
|
|
* refcount will be decremented).
|
|
*/
|
|
#define ao2_unlink_flags(container, obj, flags) \
|
|
__ao2_unlink((container), (obj), (flags), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_unlink_flags(container, obj, flags, tag) \
|
|
__ao2_unlink((container), (obj), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_unlink(struct ao2_container *c, void *obj, int flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*! @} */
|
|
|
|
|
|
/*! \brief
|
|
* ao2_callback() is a generic function that applies cb_fn() to all objects
|
|
* in a container, as described below.
|
|
*
|
|
* \param c A pointer to the container to operate on.
|
|
* \param flags A set of flags specifying the operation to perform,
|
|
* partially used by the container code, but also passed to
|
|
* the callback.
|
|
* - If OBJ_NODATA is set, ao2_callback will return NULL. No refcounts
|
|
* of any of the traversed objects will be incremented.
|
|
* On the converse, if it is NOT set (the default), the ref count
|
|
* of the first matching object will be incremented and returned.
|
|
* - If OBJ_MULTIPLE is set, the ref count of all matching objects will
|
|
* be incremented in an iterator for a temporary container and returned.
|
|
* - If OBJ_SEARCH_OBJECT is set, the traversed items will be restricted
|
|
* to the objects in the bucket that the object key hashes to.
|
|
* - If OBJ_SEARCH_KEY is set, the traversed items will be restricted
|
|
* to the objects in the bucket that the object key hashes to.
|
|
* \param cb_fn A function pointer, that will be called on all
|
|
* objects, to see if they match. This function returns CMP_MATCH
|
|
* if the object is matches the criteria; CMP_STOP if the traversal
|
|
* should immediately stop, or both (via bitwise ORing), if you find a
|
|
* match and want to end the traversal, and 0 if the object is not a match,
|
|
* but the traversal should continue. This is the function that is applied
|
|
* to each object traversed. Its arguments are:
|
|
* (void *obj, void *arg, int flags), where:
|
|
* obj is an object
|
|
* arg is the same as arg passed into ao2_callback
|
|
* flags is the same as flags passed into ao2_callback (flags are
|
|
* also used by ao2_callback).
|
|
* \param arg passed to the callback.
|
|
*
|
|
* \retval NULL on failure or no matching object found.
|
|
*
|
|
* \return object found if OBJ_MULTIPLE is not set in the flags
|
|
* parameter.
|
|
*
|
|
* \return ao2_iterator pointer if OBJ_MULTIPLE is set in the
|
|
* flags parameter. The iterator must be destroyed with
|
|
* ao2_iterator_destroy() when the caller no longer needs it.
|
|
*
|
|
* If the function returns any objects, their refcount is incremented,
|
|
* and the caller is in charge of decrementing them once done.
|
|
*
|
|
* Typically, ao2_callback() is used for two purposes:
|
|
* - to perform some action (including removal from the container) on one
|
|
* or more objects; in this case, cb_fn() can modify the object itself,
|
|
* and to perform deletion should set CMP_MATCH on the matching objects,
|
|
* and have OBJ_UNLINK set in flags.
|
|
* - to look for a specific object in a container; in this case, cb_fn()
|
|
* should not modify the object, but just return a combination of
|
|
* CMP_MATCH and CMP_STOP on the desired object.
|
|
* Other usages are also possible, of course.
|
|
*
|
|
* This function searches through a container and performs operations
|
|
* on objects according on flags passed.
|
|
* XXX describe better
|
|
* The comparison is done calling the compare function set implicitly.
|
|
* The arg pointer can be a pointer to an object or to a key,
|
|
* we can say this looking at flags value.
|
|
* If arg points to an object we will search for the object pointed
|
|
* by this value, otherwise we search for a key value.
|
|
* If the key is not unique we only find the first matching value.
|
|
*
|
|
* The use of flags argument is the follow:
|
|
*
|
|
* OBJ_UNLINK unlinks the object found
|
|
* OBJ_NODATA on match, do not return an object
|
|
* Callbacks use OBJ_NODATA as a default
|
|
* functions such as find() do
|
|
* OBJ_MULTIPLE return multiple matches
|
|
* Default is no.
|
|
* OBJ_SEARCH_OBJECT the pointer is to an object
|
|
* OBJ_SEARCH_KEY the pointer is to a search key
|
|
* OBJ_SEARCH_PARTIAL_KEY the pointer is to a partial search key
|
|
*
|
|
* \note When the returned object is no longer in use, ao2_ref() should
|
|
* be used to free the additional reference possibly created by this function.
|
|
*
|
|
* @{
|
|
*/
|
|
#define ao2_callback(c, flags, cb_fn, arg) \
|
|
__ao2_callback((c), (flags), (cb_fn), (arg), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
#define ao2_t_callback(c, flags, cb_fn, arg, tag) \
|
|
__ao2_callback((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
|
|
ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
|
|
const char *func);
|
|
|
|
/*! @} */
|
|
|
|
/*! \brief
|
|
* ao2_callback_data() is a generic function that applies cb_fn() to all objects
|
|
* in a container. It is functionally identical to ao2_callback() except that
|
|
* instead of taking an ao2_callback_fn *, it takes an ao2_callback_data_fn *, and
|
|
* allows the caller to pass in arbitrary data.
|
|
*
|
|
* This call would be used instead of ao2_callback() when the caller needs to pass
|
|
* OBJ_SEARCH_OBJECT, OBJ_SEARCH_KEY, or OBJ_SEARCH_PARTIAL_KEY as part of the flags
|
|
* argument (which in turn requires passing in a known pointer type for 'arg') and
|
|
* also needs access to other non-global data to complete it's comparison or task.
|
|
*
|
|
* See the documentation for ao2_callback() for argument descriptions.
|
|
*
|
|
* \see ao2_callback()
|
|
*/
|
|
|
|
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag) \
|
|
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_callback_data(container, flags, cb_fn, arg, data) \
|
|
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
|
|
ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
|
|
int line, const char *func);
|
|
|
|
/*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
|
|
* XXX possibly change order of arguments ?
|
|
*/
|
|
|
|
#define ao2_t_find(container, arg, flags, tag) \
|
|
__ao2_find((container), (arg), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_find(container, arg, flags) \
|
|
__ao2_find((container), (arg), (flags), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*!
|
|
* \brief Perform an ao2_find on a container with ao2_weakproxy objects, returning the real object.
|
|
*
|
|
* \note Only OBJ_SEARCH_* and OBJ_NOLOCK flags are supported by this function.
|
|
* \see ao2_callback for description of arguments.
|
|
*/
|
|
#define ao2_weakproxy_find(c, arg, flags, tag) \
|
|
__ao2_weakproxy_find(c, arg, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
void *__ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags,
|
|
const char *tag, const char *file, int line, const char *func);
|
|
|
|
/*! \brief
|
|
*
|
|
*
|
|
* When we need to walk through a container, we use an
|
|
* ao2_iterator to keep track of the current position.
|
|
*
|
|
* Because the navigation is typically done without holding the
|
|
* lock on the container across the loop, objects can be
|
|
* inserted or deleted or moved while we work. As a
|
|
* consequence, there is no guarantee that we manage to touch
|
|
* all the elements in the container, and it is possible that we
|
|
* touch the same object multiple times.
|
|
*
|
|
* An iterator must be first initialized with
|
|
* ao2_iterator_init(), then we can use o = ao2_iterator_next()
|
|
* to move from one element to the next. Remember that the
|
|
* object returned by ao2_iterator_next() has its refcount
|
|
* incremented, and the reference must be explicitly released
|
|
* when done with it.
|
|
*
|
|
* In addition, ao2_iterator_init() will hold a reference to the
|
|
* container being iterated and the last container node found.
|
|
* These objects will be unreffed when ao2_iterator_destroy() is
|
|
* called to free up the resources used by the iterator (if
|
|
* any).
|
|
*
|
|
* Example:
|
|
*
|
|
* \code
|
|
*
|
|
* struct ao2_container *c = ... // the container we want to iterate on
|
|
* struct ao2_iterator i;
|
|
* struct my_obj *o;
|
|
*
|
|
* i = ao2_iterator_init(c, flags);
|
|
*
|
|
* while ((o = ao2_iterator_next(&i))) {
|
|
* ... do something on o ...
|
|
* ao2_ref(o, -1);
|
|
* }
|
|
*
|
|
* ao2_iterator_restart(&i);
|
|
* while ((o = ao2_iterator_next(&i))) {
|
|
* ... do something on o ...
|
|
* ao2_ref(o, -1);
|
|
* }
|
|
*
|
|
* ao2_iterator_destroy(&i);
|
|
*
|
|
* \endcode
|
|
*
|
|
*/
|
|
|
|
/*!
|
|
* \brief The astobj2 iterator
|
|
*
|
|
* \note You are not supposed to know the internals of an iterator!
|
|
* We would like the iterator to be opaque, unfortunately
|
|
* its size needs to be known if we want to store it around
|
|
* without too much trouble.
|
|
* Anyways...
|
|
* The iterator has a pointer to the container, and a flags
|
|
* field specifying various things e.g. whether the container
|
|
* should be locked or not while navigating on it.
|
|
* The iterator "points" to the current container node.
|
|
*
|
|
* Details are in the implementation of ao2_iterator_next()
|
|
*/
|
|
struct ao2_iterator {
|
|
/*! The container (Has a reference) */
|
|
struct ao2_container *c;
|
|
/*! Last container node (Has a reference) */
|
|
void *last_node;
|
|
/*! Nonzero if the iteration has completed. */
|
|
int complete;
|
|
/*! operation flags (enum ao2_iterator_flags) */
|
|
int flags;
|
|
};
|
|
|
|
/*! Flags that can be passed to ao2_iterator_init() to modify the behavior
|
|
* of the iterator.
|
|
*/
|
|
enum ao2_iterator_flags {
|
|
/*!
|
|
* \brief Assume that the ao2_container is already locked.
|
|
*
|
|
* \note For ao2_containers that have mutexes, no locking will
|
|
* be done.
|
|
*
|
|
* \note For ao2_containers that have RWLOCKs, the lock will be
|
|
* promoted to write mode as needed. The lock will be returned
|
|
* to the original locked state.
|
|
*
|
|
* \note Only use this flag if the ao2_container is manually
|
|
* locked already. You should hold the lock until after
|
|
* ao2_iterator_destroy(). If you must release the lock then
|
|
* you must at least hold the lock whenever you call an
|
|
* ao2_iterator_xxx function with this iterator.
|
|
*/
|
|
AO2_ITERATOR_DONTLOCK = (1 << 0),
|
|
/*!
|
|
* Indicates that the iterator was dynamically allocated by
|
|
* astobj2 API and should be freed by ao2_iterator_destroy().
|
|
*/
|
|
AO2_ITERATOR_MALLOCD = (1 << 1),
|
|
/*!
|
|
* Indicates that before the iterator returns an object from
|
|
* the container being iterated, the object should be unlinked
|
|
* from the container.
|
|
*/
|
|
AO2_ITERATOR_UNLINK = (1 << 2),
|
|
/*!
|
|
* Iterate in descending order (Last to first container object)
|
|
* (Otherwise ascending order)
|
|
*
|
|
* \note Other traversal orders such as pre-order and post-order
|
|
* do not make sense because they require the container
|
|
* structure to be static during the traversal. Iterators just
|
|
* about guarantee that is not going to happen because the
|
|
* container is allowed to change by other threads during the
|
|
* iteration.
|
|
*/
|
|
AO2_ITERATOR_DESCENDING = (1 << 3),
|
|
};
|
|
|
|
/*!
|
|
* \brief Create an iterator for a container
|
|
*
|
|
* \param c the container
|
|
* \param flags one or more flags from ao2_iterator_flags.
|
|
*
|
|
* \return the constructed iterator
|
|
*
|
|
* \note This function does \b not take a pointer to an iterator;
|
|
* rather, it returns an iterator structure that should be
|
|
* assigned to (overwriting) an existing iterator structure
|
|
* allocated on the stack or on the heap.
|
|
*
|
|
* This function will take a reference on the container being iterated.
|
|
*/
|
|
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Destroy a container iterator
|
|
*
|
|
* \param iter the iterator to destroy
|
|
*
|
|
* This function will release the container reference held by the iterator
|
|
* and any other resources it may be holding.
|
|
*/
|
|
#if defined(TEST_FRAMEWORK)
|
|
void ao2_iterator_destroy(struct ao2_iterator *iter) __attribute__((noinline));
|
|
#else
|
|
void ao2_iterator_destroy(struct ao2_iterator *iter);
|
|
#endif /* defined(TEST_FRAMEWORK) */
|
|
|
|
#define ao2_t_iterator_next(iter, tag) \
|
|
__ao2_iterator_next((iter), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_iterator_next(iter) \
|
|
__ao2_iterator_next((iter), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
|
|
void *__ao2_iterator_next(struct ao2_iterator *iter,
|
|
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
|
|
|
|
/*!
|
|
* \brief Restart an iteration.
|
|
*
|
|
* \param iter the iterator to restart
|
|
*
|
|
* \note A restart is not going to have any effect if the
|
|
* iterator was created with the AO2_ITERATOR_UNLINK flag. Any
|
|
* previous objects returned were removed from the container.
|
|
*/
|
|
void ao2_iterator_restart(struct ao2_iterator *iter);
|
|
|
|
/*! gcc __attribute__(cleanup()) functions
|
|
* \note they must be able to handle NULL parameters because most of the
|
|
* allocation/find functions can fail and we don't want to try to tear
|
|
* down a NULL */
|
|
void __ao2_cleanup(void *obj);
|
|
void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function);
|
|
#define ao2_cleanup(obj) __ao2_cleanup_debug((obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
#define ao2_t_cleanup(obj, tag) __ao2_cleanup_debug((obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
void ao2_iterator_cleanup(struct ao2_iterator *iter);
|
|
|
|
/*!
|
|
* \brief Get a count of the iterated container objects.
|
|
*
|
|
* \param iter the iterator to query
|
|
*
|
|
* \return The number of objects in the iterated container
|
|
*/
|
|
int ao2_iterator_count(struct ao2_iterator *iter);
|
|
|
|
/*!
|
|
* \brief Creates a hash function for a structure field.
|
|
* \param stype The structure type
|
|
* \param field The string field in the structure to hash
|
|
* \param hash_fn Function which hashes the field
|
|
*
|
|
* AO2_FIELD_HASH_FN(mystruct, myfield, ast_str_hash) will
|
|
* produce a function named mystruct_hash_fn which hashes
|
|
* mystruct->myfield with ast_str_hash.
|
|
*/
|
|
#define AO2_FIELD_HASH_FN(stype, field, hash_fn) \
|
|
static int stype ## _hash_fn(const void *obj, const int flags) \
|
|
{ \
|
|
const struct stype *object = obj; \
|
|
const char *key; \
|
|
switch (flags & OBJ_SEARCH_MASK) { \
|
|
case OBJ_SEARCH_KEY: \
|
|
key = obj; \
|
|
break; \
|
|
case OBJ_SEARCH_OBJECT: \
|
|
key = object->field; \
|
|
break; \
|
|
default: \
|
|
ast_assert(0); \
|
|
return 0; \
|
|
} \
|
|
return hash_fn(key); \
|
|
}
|
|
|
|
|
|
#define AO2_FIELD_TRANSFORM_CMP_FN(cmp) ((cmp) ? 0 : CMP_MATCH)
|
|
#define AO2_FIELD_TRANSFORM_SORT_FN(cmp) (cmp)
|
|
|
|
/*!
|
|
* \internal
|
|
*
|
|
* \brief Creates a compare function for a structure string field.
|
|
* \param stype The structure type
|
|
* \param fn_suffix Function name suffix
|
|
* \param field The string field in the structure to compare
|
|
* \param key_cmp Key comparison function like strcmp
|
|
* \param partial_key_cmp Partial key comparison function like strncmp
|
|
* \param transform A macro that takes the cmp result as an argument
|
|
* and transforms it to a return value.
|
|
* \param argconst
|
|
*
|
|
* Do not use this macro directly, instead use macro's starting with
|
|
* AST_STRING_FIELD.
|
|
*
|
|
* \warning The macro is an internal implementation detail, the API
|
|
* may change at any time.
|
|
*/
|
|
#define AO2_FIELD_CMP_FN(stype, fn_suffix, field, key_cmp, partial_key_cmp, transform, argconst) \
|
|
static int stype ## fn_suffix(argconst void *obj, argconst void *arg, int flags) \
|
|
{ \
|
|
const struct stype *object_left = obj, *object_right = arg; \
|
|
const char *right_key = arg; \
|
|
int cmp; \
|
|
switch (flags & OBJ_SEARCH_MASK) { \
|
|
case OBJ_SEARCH_OBJECT: \
|
|
right_key = object_right->field; \
|
|
case OBJ_SEARCH_KEY: \
|
|
cmp = key_cmp(object_left->field, right_key); \
|
|
break; \
|
|
case OBJ_SEARCH_PARTIAL_KEY: \
|
|
cmp = partial_key_cmp(object_left->field, right_key, strlen(right_key)); \
|
|
break; \
|
|
default: \
|
|
cmp = 0; \
|
|
break; \
|
|
} \
|
|
return transform(cmp); \
|
|
}
|
|
|
|
/*!
|
|
* \brief Creates a hash function for a structure string field.
|
|
* \param stype The structure type
|
|
* \param field The string field in the structure to hash
|
|
*
|
|
* AO2_STRING_FIELD_HASH_FN(mystruct, myfield) will produce a function
|
|
* named mystruct_hash_fn which hashes mystruct->myfield.
|
|
*
|
|
* AO2_STRING_FIELD_HASH_FN(mystruct, myfield) would do the same except
|
|
* it uses the hash function which ignores case.
|
|
*/
|
|
#define AO2_STRING_FIELD_HASH_FN(stype, field) \
|
|
AO2_FIELD_HASH_FN(stype, field, ast_str_hash)
|
|
#define AO2_STRING_FIELD_CASE_HASH_FN(stype, field) \
|
|
AO2_FIELD_HASH_FN(stype, field, ast_str_case_hash)
|
|
|
|
/*!
|
|
* \brief Creates a compare function for a structure string field.
|
|
* \param stype The structure type
|
|
* \param field The string field in the structure to compare
|
|
*
|
|
* AO2_STRING_FIELD_CMP_FN(mystruct, myfield) will produce a function
|
|
* named mystruct_cmp_fn which compares mystruct->myfield.
|
|
*
|
|
* AO2_STRING_FIELD_CASE_CMP_FN(mystruct, myfield) would do the same
|
|
* except it performs case insensitive comparisons.
|
|
*/
|
|
#define AO2_STRING_FIELD_CMP_FN(stype, field) \
|
|
AO2_FIELD_CMP_FN(stype, _cmp_fn, field, strcmp, strncmp, AO2_FIELD_TRANSFORM_CMP_FN,)
|
|
#define AO2_STRING_FIELD_CASE_CMP_FN(stype, field) \
|
|
AO2_FIELD_CMP_FN(stype, _cmp_fn, field, strcasecmp, strncasecmp, AO2_FIELD_TRANSFORM_CMP_FN,)
|
|
|
|
/*!
|
|
* \brief Creates a sort function for a structure string field.
|
|
* \param stype The structure type
|
|
* \param field The string field in the structure to compare
|
|
*
|
|
* AO2_STRING_FIELD_SORT_FN(mystruct, myfield) will produce a function
|
|
* named mystruct_sort_fn which compares mystruct->myfield.
|
|
*
|
|
* AO2_STRING_FIELD_CASE_SORT_FN(mystruct, myfield) would do the same
|
|
* except it performs case insensitive comparisons.
|
|
*/
|
|
#define AO2_STRING_FIELD_SORT_FN(stype, field) \
|
|
AO2_FIELD_CMP_FN(stype, _sort_fn, field, strcmp, strncmp, AO2_FIELD_TRANSFORM_SORT_FN, const)
|
|
#define AO2_STRING_FIELD_CASE_SORT_FN(stype, field) \
|
|
AO2_FIELD_CMP_FN(stype, _sort_fn, field, strcasecmp, strncasecmp, AO2_FIELD_TRANSFORM_SORT_FN, const)
|
|
|
|
#endif /* _ASTERISK_ASTOBJ2_H */
|