[asterisk-commits] rmudgett: branch rmudgett/ao2_enhancements r342542 - in /team/rmudgett/ao2_en...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Oct 26 16:40:25 CDT 2011
Author: rmudgett
Date: Wed Oct 26 16:40:21 2011
New Revision: 342542
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=342542
Log:
Initial ao2 locking enhancements to add no-lock and rwlock options to objects.
Now to make the rest of the system use OBJ_NOLOCK and
AO2_ITERATOR_DONTLOCK correctly with the new locking options.
Modified:
team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
team/rmudgett/ao2_enhancements/include/asterisk/lock.h
team/rmudgett/ao2_enhancements/main/astobj2.c
Modified: team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h?view=diff&rev=342542&r1=342541&r2=342542
==============================================================================
--- team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h (original)
+++ team/rmudgett/ao2_enhancements/include/asterisk/astobj2.h Wed Oct 26 16:40:21 2011
@@ -383,15 +383,28 @@
*/
typedef void (*ao2_destructor_fn)(void *);
-
-/*! \brief
- * Allocate and initialize an object.
+/*! \brief Options available when allocating an ao2 object. */
+enum ao2_alloc_opts {
+ /*! Ao2 object has a recursive mutex lock associated with it. */
+ AO2_ALLOC_OPT_LOCK_MUTEX = (0 << 0),
+ /*! Ao2 object has a non-recursive read/write lock associated with it. */
+ AO2_ALLOC_OPT_LOCK_RWLOCK = (1 << 0),
+ /*! Ao2 object has no lock associated with it. */
+ AO2_ALLOC_OPT_LOCK_NOLOCK = (2 << 0),
+ /*! Ao2 object locking option field mask. */
+ AO2_ALLOC_OPT_LOCK_MASK = (3 << 0),
+};
+
+/*!
+ * \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 debug_msg
+ * \param options Ao2 object options (See enum ao2_alloc_opts)
+ * \param debug_msg 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
@@ -405,24 +418,36 @@
#if defined(REF_DEBUG)
-#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-#define ao2_alloc(data_size, destructor_fn) __ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg) \
+ __ao2_alloc_debug((data_size), (destructor_fn), (options), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
+ __ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_alloc(data_size, destructor_fn) \
+ __ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
-#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc_debug((data_size), (destructor_fn), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_alloc(data_size, destructor_fn) __ao2_alloc_debug((data_size), (destructor_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg) \
+ __ao2_alloc_debug((data_size), (destructor_fn), (options), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
+ __ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_alloc(data_size, destructor_fn) \
+ __ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
-#define ao2_t_alloc(data_size, destructor_fn, debug_msg) __ao2_alloc((data_size), (destructor_fn))
-#define ao2_alloc(data_size, destructor_fn) __ao2_alloc((data_size), (destructor_fn))
+#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg) \
+ __ao2_alloc((data_size), (destructor_fn), (options))
+#define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
+ __ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX)
+#define ao2_alloc(data_size, destructor_fn) \
+ __ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX)
#endif
-void *__ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag,
- const char *file, int line, const char *funcname, int ref_debug);
-void *__ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn);
+void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
+ const char *file, int line, const char *funcname, int ref_debug);
+void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options);
/*! @} */
@@ -462,10 +487,20 @@
#endif
-int __ao2_ref_debug(void *o, int delta, char *tag, char *file, int line, const char *funcname);
+int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *funcname);
int __ao2_ref(void *o, int delta);
/*! @} */
+
+/*! \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.
@@ -473,8 +508,10 @@
* \param a A pointer to the object we want to lock.
* \return 0 on success, other values on error.
*/
-int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
-#define ao2_lock(a) __ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+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.
@@ -491,14 +528,16 @@
* \param a A pointer to the object we want to lock.
* \return 0 on success, other values on error.
*/
-int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
-#define ao2_trylock(a) __ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+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 lock address of an object
+ * \brief Return the mutex lock address of an object
*
* \param[in] obj A pointer to the object we want.
- * \return the address of the lock, else NULL.
+ * \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
@@ -518,13 +557,13 @@
data structures depending on the needs.
\note NOTA BENE: at the moment the only container we support is the
- hash table and its degenerate form, the list.
+ hash table and its degenerate form, the list.
Operations on container include:
- c = \b ao2_container_alloc(size, hash_fn, cmp_fn)
- allocate a container with desired size and default compare
- and hash function
+ allocate a container with desired size and default compare
+ and hash function
-The compare function returns an int, which
can be 0 for not found, CMP_STOP to stop end a traversal,
or CMP_MATCH if they are equal
@@ -532,27 +571,31 @@
takes two argument, the object pointer and a flags field,
- \b ao2_find(c, arg, flags)
- returns zero or more element matching a given criteria
- (specified as arg). 'c' is the container pointer. 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_POINTER - if set, 'arg' is an object pointer, and a hash table
+ 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_POINTER - if set, 'arg' is an object pointer, and a hash table
search will be done. If not, a traversal is done.
+ OBJ_KEY - if set, 'arg', is a hashable item that is not an object.
+ Similar to OBJ_POINTER 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;
+ 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_POINTER - if set, 'arg' is an object pointer, and a hash table
+ 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_POINTER - 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_KEY - if set, 'arg', is a hashable item that is not an object.
+ Similar to OBJ_POINTER and mutually exclusive.
- fn is a func that returns int, and takes 3 args:
(void *obj, void *arg, int flags);
obj is an object
@@ -563,39 +606,39 @@
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.
+ 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
+ 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);
+ 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.
+ 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!
+ dropping a reference to a container destroys it, very simple!
Containers are ao2 objects themselves, and this is why their
implementation is simple too.
@@ -650,11 +693,11 @@
/*! Unlink the object for which the callback function
* returned CMP_MATCH.
*/
- OBJ_UNLINK = (1 << 0),
+ OBJ_UNLINK = (1 << 0),
/*! On match, don't return the object hence do not increase
* its refcount.
*/
- OBJ_NODATA = (1 << 1),
+ OBJ_NODATA = (1 << 1),
/*! Don't stop at the first match in ao2_callback() unless the result of
* of the callback function == (CMP_STOP | CMP_MATCH).
*/
@@ -664,8 +707,8 @@
* The search function is unaffected (i.e. use the one passed as
* argument, or match_by_addr if none specified).
*/
- OBJ_POINTER = (1 << 3),
- /*!
+ OBJ_POINTER = (1 << 3),
+ /*!
* \brief Continue if a match is not found in the hashed out bucket
*
* This flag is to be used in combination with OBJ_POINTER. This tells
@@ -673,23 +716,33 @@
* buckets if a match is not found in the starting bucket defined by
* the hash value on the argument.
*/
- OBJ_CONTINUE = (1 << 4),
- /*!
- * \brief By using this flag, the ao2_container being searched will _NOT_
- * be locked. Only use this flag if the ao2_container is being protected
- * by another mechanism other that the internal ao2_lock.
+ OBJ_CONTINUE = (1 << 4),
+ /*!
+ * \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 << 5),
+ OBJ_NOLOCK = (1 << 5),
/*!
* \brief The data is hashable, but is not an object.
*
+ * \details
* This can be used when you want to be able to pass custom data
- * to a hash function that is not a full object, but perhaps just
- * a string.
+ * to the container's stored ao2_hash_fn and ao2_find
+ * ao2_callback_fn functions that is not a full object, but
+ * perhaps just a string.
*
* \note OBJ_KEY and OBJ_POINTER are mutually exclusive options.
*/
- OBJ_KEY = (1 << 6),
+ OBJ_KEY = (1 << 6),
};
/*!
@@ -705,17 +758,18 @@
/*@{ */
struct ao2_container;
-/*! \brief
- * Allocate and initialize a container
- * with the desired number of buckets.
- *
+/*!
+ * \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 arg1 Number of buckets for hash
- * \param arg2 Pointer to a function computing a hash value.
- * \param arg3 Pointer to a compare function used by ao2_find. (NULL to match everything)
- * \param arg4 used for debugging.
+ * \param options Container ao2 object options (See enum ao2_alloc_opts)
+ * \param n_buckets Number of buckets for hash
+ * \param hash_fn Pointer to a function computing a hash value.
+ * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
+ * \param tag used for debugging.
*
* \return A pointer to a struct container.
*
@@ -724,27 +778,38 @@
#if defined(REF_DEBUG)
-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
-#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
+ __ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
-#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
+ __ao2_container_alloc_debug(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) __ao2_container_alloc((arg1), (arg2), (arg3))
-#define ao2_container_alloc(arg1,arg2,arg3) __ao2_container_alloc((arg1), (arg2), (arg3))
+#define ao2_t_container_alloc_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
+#define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
+ __ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
+#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
+ __ao2_container_alloc(AO2_ALLOC_OPT_LOCK_MUTEX, (n_buckets), (hash_fn), (cmp_fn))
#endif
-struct ao2_container *__ao2_container_alloc(const unsigned int n_buckets,
- ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
-struct ao2_container *__ao2_container_alloc_debug(const unsigned int n_buckets,
- ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
- char *tag, char *file, int line, const char *funcname,
- int ref_debug);
+struct ao2_container *__ao2_container_alloc(unsigned int options,
+ unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
+struct ao2_container *__ao2_container_alloc_debug(unsigned int options,
+ unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
+ const char *tag, const char *file, int line, const char *funcname, int ref_debug);
/*! \brief
* Returns the number of elements in a container.
@@ -764,9 +829,9 @@
/*!
* \brief Add an object to a container.
*
- * \param arg1 the container to operate on.
- * \param arg2 the object to be added.
- * \param arg3 used for debugging.
+ * \param container The container to operate on.
+ * \param obj The object to be added.
+ * \param tag used for debugging.
*
* \retval NULL on errors.
* \retval newobj on success.
@@ -780,29 +845,29 @@
*/
#ifdef REF_DEBUG
-#define ao2_t_link(arg1, arg2, arg3) __ao2_link_debug((arg1), (arg2), 0, (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_link(arg1, arg2) __ao2_link_debug((arg1), (arg2), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_t_link_nolock(arg1, arg2, arg3) __ao2_link_debug((arg1), (arg2), OBJ_NOLOCK, (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_link_nolock(arg1, arg2) __ao2_link_debug((arg1), (arg2), OBJ_NOLOCK, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_link(container, obj, tag) __ao2_link_debug((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_link(container, obj) __ao2_link_debug((container), (obj), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_link_nolock(container, obj, tag) __ao2_link_debug((container), (obj), OBJ_NOLOCK, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_link_nolock(container, obj) __ao2_link_debug((container), (obj), OBJ_NOLOCK, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_link(arg1, arg2, arg3) __ao2_link((arg1), (arg2), 0)
-#define ao2_link(arg1, arg2) __ao2_link((arg1), (arg2), 0)
-#define ao2_t_link_nolock(arg1, arg2, arg3) __ao2_link((arg1), (arg2), OBJ_NOLOCK)
-#define ao2_link_nolock(arg1, arg2) __ao2_link((arg1), (arg2), OBJ_NOLOCK)
+#define ao2_t_link(container, obj, tag) __ao2_link((container), (obj), 0)
+#define ao2_link(container, obj) __ao2_link((container), (obj), 0)
+#define ao2_t_link_nolock(container, obj, tag) __ao2_link((container), (obj), OBJ_NOLOCK)
+#define ao2_link_nolock(container, obj) __ao2_link((container), (obj), OBJ_NOLOCK)
#endif
-void *__ao2_link_debug(struct ao2_container *c, void *new_obj, int flags, char *tag, char *file, int line, const char *funcname);
+void *__ao2_link_debug(struct ao2_container *c, void *new_obj, int flags, const char *tag, const char *file, int line, const char *funcname);
void *__ao2_link(struct ao2_container *c, void *newobj, int flags);
/*!
* \brief Remove an object from a container
*
- * \param arg1 the container
- * \param arg2 the object to unlink
- * \param arg3 tag for debugging
+ * \param container The container to operate on.
+ * \param obj The object to unlink.
+ * \param tag used for debugging.
*
* \retval NULL, always
*
@@ -816,21 +881,21 @@
*/
#ifdef REF_DEBUG
-#define ao2_t_unlink(arg1, arg2, arg3) __ao2_unlink_debug((arg1), (arg2), 0, (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_unlink(arg1, arg2) __ao2_unlink_debug((arg1), (arg2), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_t_unlink_nolock(arg1, arg2, arg3) __ao2_unlink_debug((arg1), (arg2), OBJ_NOLOCK, (arg3), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_unlink_nolock(arg1, arg2) __ao2_unlink_debug((arg1), (arg2), OBJ_NOLOCK, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_unlink(container, obj, tag) __ao2_unlink_debug((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_unlink(container, obj) __ao2_unlink_debug((container), (obj), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_unlink_nolock(container, obj, tag) __ao2_unlink_debug((container), (obj), OBJ_NOLOCK, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_unlink_nolock(container, obj) __ao2_unlink_debug((container), (obj), OBJ_NOLOCK, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_unlink(arg1, arg2, arg3) __ao2_unlink((arg1), (arg2), 0)
-#define ao2_unlink(arg1, arg2) __ao2_unlink((arg1), (arg2), 0)
-#define ao2_t_unlink_nolock(arg1, arg2, arg3) __ao2_unlink((arg1), (arg2), OBJ_NOLOCK)
-#define ao2_unlink_nolock(arg1, arg2) __ao2_unlink((arg1), (arg2), OBJ_NOLOCK)
+#define ao2_t_unlink(container, obj, tag) __ao2_unlink((container), (obj), 0)
+#define ao2_unlink(container, obj) __ao2_unlink((container), (obj), 0)
+#define ao2_t_unlink_nolock(container, obj, tag) __ao2_unlink((container), (obj), OBJ_NOLOCK)
+#define ao2_unlink_nolock(container, obj) __ao2_unlink((container), (obj), OBJ_NOLOCK)
#endif
-void *__ao2_unlink_debug(struct ao2_container *c, void *obj, int flags, char *tag, char *file, int line, const char *funcname);
+void *__ao2_unlink_debug(struct ao2_container *c, void *obj, int flags, const char *tag, const char *file, int line, const char *funcname);
void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
@@ -842,28 +907,28 @@
*
* \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 each object for which CMP_MATCH was set will be incremented,
- and you will have no way of knowing which those are, until
- the multiple-object-return functionality is implemented.
- - If OBJ_POINTER is set, the traversed items will be restricted
- to the objects in the bucket that the object key hashes to.
+ * 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 each object for which CMP_MATCH was set will be incremented,
+ * and you will have no way of knowing which those are, until
+ * the multiple-object-return functionality is implemented.
+ * - If OBJ_POINTER 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).
+ * 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.
* \param tag used for debugging.
* \return when OBJ_MULTIPLE is not included in the flags parameter,
@@ -885,7 +950,7 @@
* 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
@@ -898,13 +963,14 @@
*
* The use of flags argument is the follow:
*
- * OBJ_UNLINK unlinks the object found
- * OBJ_NODATA on match, do return an object
- * Callbacks use OBJ_NODATA as a default
- * functions such as find() do
- * OBJ_MULTIPLE return multiple matches
- * Default is no.
- * OBJ_POINTER the pointer is an object pointer
+ * OBJ_UNLINK unlinks the object found
+ * OBJ_NODATA on match, do return an object
+ * Callbacks use OBJ_NODATA as a default
+ * functions such as find() do
+ * OBJ_MULTIPLE return multiple matches
+ * Default is no.
+ * OBJ_POINTER the pointer is an object pointer
+ * OBJ_KEY the pointer is to a hashable 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.
@@ -913,18 +979,23 @@
*/
#ifdef REF_DEBUG
-#define ao2_t_callback(c,flags,cb_fn,arg,tag) __ao2_callback_debug((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_callback(c,flags,cb_fn,arg) __ao2_callback_debug((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_callback(c, flags, cb_fn, arg, tag) \
+ __ao2_callback_debug((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_callback(c, flags, cb_fn, arg) \
+ __ao2_callback_debug((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_callback(c,flags,cb_fn,arg,tag) __ao2_callback((c), (flags), (cb_fn), (arg))
-#define ao2_callback(c,flags,cb_fn,arg) __ao2_callback((c), (flags), (cb_fn), (arg))
+#define ao2_t_callback(c, flags, cb_fn, arg, tag) \
+ __ao2_callback((c), (flags), (cb_fn), (arg))
+#define ao2_callback(c, flags, cb_fn, arg) \
+ __ao2_callback((c), (flags), (cb_fn), (arg))
#endif
-void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn,
- void *arg, char *tag, char *file, int line, const char *funcname);
+void *__ao2_callback_debug(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 *funcname);
void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
/*! @} */
@@ -946,39 +1017,47 @@
*/
#ifdef REF_DEBUG
-#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) __ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), (arg6), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) __ao2_callback_data_debug((arg1), (arg2), (arg3), (arg4), (arg5), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag) \
+ __ao2_callback_data_debug((container), (flags), (cb_fn), (arg), (data), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_callback_data(container, flags, cb_fn, arg, data) \
+ __ao2_callback_data_debug((container), (flags), (cb_fn), (arg), (data), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_callback_data(arg1,arg2,arg3,arg4,arg5,arg6) __ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
-#define ao2_callback_data(arg1,arg2,arg3,arg4,arg5) __ao2_callback_data((arg1), (arg2), (arg3), (arg4), (arg5))
+#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag) \
+ __ao2_callback_data((container), (flags), (cb_fn), (arg), (data))
+#define ao2_callback_data(container, flags, cb_fn, arg, data) \
+ __ao2_callback_data((container), (flags), (cb_fn), (arg), (data))
#endif
void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
- ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag,
- char *file, int line, const char *funcname);
+ ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
+ int line, const char *funcname);
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
- ao2_callback_data_fn *cb_fn, void *arg, void *data);
+ ao2_callback_data_fn *cb_fn, void *arg, void *data);
/*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
* XXX possibly change order of arguments ?
*/
#ifdef REF_DEBUG
-#define ao2_t_find(arg1,arg2,arg3,arg4) __ao2_find_debug((arg1), (arg2), (arg3), (arg4), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_find(arg1,arg2,arg3) __ao2_find_debug((arg1), (arg2), (arg3), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_find(container, arg, flags, tag) \
+ __ao2_find_debug((container), (arg), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_find(container, arg, flags) \
+ __ao2_find_debug((container), (arg), (flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_find(arg1,arg2,arg3,arg4) __ao2_find((arg1), (arg2), (arg3))
-#define ao2_find(arg1,arg2,arg3) __ao2_find((arg1), (arg2), (arg3))
+#define ao2_t_find(container, arg, flags, tag) \
+ __ao2_find((container), (arg), (flags))
+#define ao2_find(container, arg, flags) \
+ __ao2_find((container), (arg), (flags))
#endif
-void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags, char *tag,
- char *file, int line, const char *funcname);
+void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
+ const char *tag, const char *file, int line, const char *funcname);
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags);
/*! \brief
@@ -1081,8 +1160,18 @@
* of the iterator.
*/
enum ao2_iterator_flags {
- /*! Prevents ao2_iterator_next() from locking the container
- * while retrieving the next object from it.
+ /*!
+ * \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.
*/
AO2_ITERATOR_DONTLOCK = (1 << 0),
/*! Indicates that the iterator was dynamically allocated by
@@ -1129,17 +1218,17 @@
#ifdef REF_DEBUG
-#define ao2_t_iterator_next(arg1, arg2) __ao2_iterator_next_debug((arg1), (arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_iterator_next(arg1) __ao2_iterator_next_debug((arg1), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_iterator_next(iter, tag) __ao2_iterator_next_debug((iter), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_iterator_next(iter) __ao2_iterator_next_debug((iter), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
-#define ao2_t_iterator_next(arg1, arg2) __ao2_iterator_next((arg1))
-#define ao2_iterator_next(arg1) __ao2_iterator_next((arg1))
+#define ao2_t_iterator_next(iter, tag) __ao2_iterator_next((iter))
+#define ao2_iterator_next(iter) __ao2_iterator_next((iter))
#endif
-void *__ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname);
+void *__ao2_iterator_next_debug(struct ao2_iterator *a, const char *tag, const char *file, int line, const char *funcname);
void *__ao2_iterator_next(struct ao2_iterator *a);
/* extra functions */
Modified: team/rmudgett/ao2_enhancements/include/asterisk/lock.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/include/asterisk/lock.h?view=diff&rev=342542&r1=342541&r2=342542
==============================================================================
--- team/rmudgett/ao2_enhancements/include/asterisk/lock.h (original)
+++ team/rmudgett/ao2_enhancements/include/asterisk/lock.h Wed Oct 26 16:40:21 2011
@@ -352,7 +352,7 @@
if (__res2) { \
ast_log(LOG_WARNING, "Could not unlock channel '%s': %s. {{{Originally locked at %s line %d: (%s) '%s'}}} I will NOT try to relock.\n", #chan, strerror(__res2), __filename, __lineno, __func, __mutex_name); \
} else { \
- __ao2_lock(chan, __filename, __func, __lineno, __mutex_name); \
+ __ao2_lock(chan, AO2_LOCK_REQ_MUTEX, __filename, __func, __lineno, __mutex_name); \
} \
} \
} while (0)
Modified: team/rmudgett/ao2_enhancements/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_enhancements/main/astobj2.c?view=diff&rev=342542&r1=342541&r2=342542
==============================================================================
--- team/rmudgett/ao2_enhancements/main/astobj2.c (original)
+++ team/rmudgett/ao2_enhancements/main/astobj2.c Wed Oct 26 16:40:21 2011
@@ -27,22 +27,26 @@
#include "asterisk/cli.h"
#define REF_FILE "/tmp/refs"
+#if defined(TEST_FRAMEWORK)
+/* We are building with the test framework enabled so enagle AO2 debug tests as well. */
+#define AO2_DEBUG 1
+#endif /* defined(TEST_FRAMEWORK) */
+
/*!
* astobj2 objects are always preceded by this data structure,
- * which contains a lock, a reference counter,
- * the flags and a pointer to a destructor.
+ * which contains a reference counter,
+ * option flags and a pointer to a destructor.
* The refcount is used to decide when it is time to
* invoke the destructor.
* The magic number is used for consistency check.
- * XXX the lock is not always needed, and its initialization may be
- * expensive. Consider making it external.
*/
struct __priv_data {
- ast_mutex_t lock;
int ref_counter;
ao2_destructor_fn destructor_fn;
- /*! for stats */
+ /*! User data size for stats */
size_t data_size;
+ /*! Ao2 object option flags */
+ uint32_t options;
/*! magic number. This is used to verify that a pointer passed in is a
* valid astobj2 */
uint32_t magic;
@@ -59,9 +63,29 @@
void *user_data[0];
};
-#ifdef AST_DEVMODE
-/* #define AO2_DEBUG 1 */
-#endif
+struct ao2_lock_priv {
+ ast_mutex_t lock;
+};
+
+/* AstObj2 with recursive lock. */
+struct astobj2_lock {
+ struct ao2_lock_priv mutex;
+ struct __priv_data priv_data;
+ void *user_data[0];
+};
+
+struct ao2_rwlock_priv {
+ ast_rwlock_t lock;
+ /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
+ int num_lockers;
+};
+
+/* AstObj2 with RW lock. */
+struct astobj2_rwlock {
+ struct ao2_rwlock_priv rwlock;
+ struct __priv_data priv_data;
+ void *user_data[0];
+};
#ifdef AO2_DEBUG
struct ao2_stats {
@@ -97,6 +121,12 @@
}
#endif
+#define INTERNAL_OBJ_MUTEX(user_data) \
+ ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
+
+#define INTERNAL_OBJ_RWLOCK(user_data) \
+ ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
+
/*!
* \brief convert from a pointer _p to a user-defined object
*
@@ -114,7 +144,7 @@
p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
if (AO2_MAGIC != (p->priv_data.magic) ) {
ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
- p = NULL;
+ return NULL;
}
return p;
@@ -132,80 +162,345 @@
*/
#define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
-/* the underlying functions common to debug and non-debug versions */
-
-static int internal_ao2_ref(void *user_data, const int delta);
-static struct ao2_container *internal_ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
- ao2_callback_fn *cmp_fn);
-static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, int flags, const char *file, int line, const char *func);
-static void *internal_ao2_callback(struct ao2_container *c,
- const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
- char *tag, char *file, int line, const char *funcname);
[... 1150 lines stripped ...]
More information about the asterisk-commits
mailing list