[asterisk-commits] rmudgett: trunk r357272 - in /trunk: include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Feb 28 12:15:41 CST 2012


Author: rmudgett
Date: Tue Feb 28 12:15:34 2012
New Revision: 357272

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=357272
Log:
Astobj2 locking enhancement.

Add the ability to specify what kind of locking an ao2 object has when it
is allocated.  The locking could be one of: MUTEX, RWLOCK, or none.

New API:

ao2_t_alloc_options()
ao2_alloc_options()
ao2_t_container_alloc_options()
ao2_container_alloc_options()

ao2_rdlock()
ao2_wrlock()
ao2_tryrdlock()
ao2_trywrlock()

The OBJ_NOLOCK and AO2_ITERATOR_DONTLOCK flags have a slight meaning
change.  They no longer mean that the object is protected by an external
mechanism.  They mean the lock associated with the object has already been
manually obtained by one of the ao2_lock calls.  This change is necessary
for RWLOCK support since they are not reentrant.  Also an operation on an
ao2 container may require promoting a read lock to a write lock by
releasing the already held read lock to re-acquire as a write lock.


Replaced API calls:

ao2_t_link_nolock()
ao2_link_nolock()
ao2_t_unlink_nolock()
ao2_unlink_nolock()

with the respective

ao2_t_link_flags()
ao2_link_flags()
ao2_t_unlink_flags()
ao2_unlink_flags()

API calls to be more flexible and to allow an anticipated enhancement to
control linking duplicate objects into a container.


The changes to format.c and format_cap.c are taking advantange of the new
ao2 locking options to simplify the use of the format capabilities
containers.

Review: https://reviewboard.asterisk.org/r/1554/

Modified:
    trunk/include/asterisk/astobj2.h
    trunk/include/asterisk/lock.h
    trunk/main/astobj2.c
    trunk/main/format.c
    trunk/main/format_cap.c

Modified: trunk/include/asterisk/astobj2.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/astobj2.h?view=diff&rev=357272&r1=357271&r2=357272
==============================================================================
--- trunk/include/asterisk/astobj2.h (original)
+++ trunk/include/asterisk/astobj2.h Tue Feb 28 12:15:34 2012
@@ -390,12 +390,24 @@
  */
 typedef void (*ao2_destructor_fn)(void *);
 
+/*! \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),
+};
 
 /*!
  * \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.
  *
@@ -413,30 +425,45 @@
 
 #if defined(REF_DEBUG)
 
+#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_alloc_options(data_size, destructor_fn, options) \
+	__ao2_alloc_debug((data_size), (destructor_fn), (options), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
 #define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
-	__ao2_alloc_debug((data_size), (destructor_fn), (debug_msg),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	__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), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	__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_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_alloc_options(data_size, destructor_fn, options) \
+	__ao2_alloc_debug((data_size), (destructor_fn), (options), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
 #define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
-	__ao2_alloc_debug((data_size), (destructor_fn), (debug_msg),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+	__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), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+	__ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
 
 #else
 
+#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg) \
+	__ao2_alloc((data_size), (destructor_fn), (options))
+#define ao2_alloc_options(data_size, destructor_fn, options) \
+	__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((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX)
 #define ao2_alloc(data_size, destructor_fn) \
-	__ao2_alloc((data_size), (destructor_fn))
+	__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX)
 
 #endif
 
-void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, const char *tag,
+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);
+void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options);
 
 /*! @} */
 
@@ -476,10 +503,20 @@
 
 #endif
 
-int __ao2_ref_debug(void *o, int delta, const 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.
@@ -487,8 +524,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.
@@ -505,8 +544,10 @@
  * \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 mutex lock address of an object
@@ -693,9 +734,17 @@
 	 */
 	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.
+	 * \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),
 	/*!
@@ -732,6 +781,7 @@
  * We allocate space for a struct astobj_container, struct container
  * and the buckets[] array.
  *
+ * \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)
@@ -744,32 +794,47 @@
 
 #if defined(REF_DEBUG)
 
+#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_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+
 #define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug((n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	__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((n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
+	__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_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_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
+	__ao2_container_alloc_debug((options), (n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+
 #define ao2_t_container_alloc(n_buckets, hash_fn, cmp_fn, tag) \
-	__ao2_container_alloc_debug((n_buckets), (hash_fn), (cmp_fn), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+	__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((n_buckets), (hash_fn), (cmp_fn), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
+	__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_options(options, n_buckets, hash_fn, cmp_fn, tag) \
+	__ao2_container_alloc((options), (n_buckets), (hash_fn), (cmp_fn))
+#define ao2_container_alloc_options(options, n_buckets, hash_fn, cmp_fn) \
+	__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((n_buckets), (hash_fn), (cmp_fn))
+	__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((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(unsigned int n_buckets, ao2_hash_fn *hash_fn,
-	ao2_callback_fn *cmp_fn);
-struct ao2_container *__ao2_container_alloc_debug(unsigned int n_buckets,
-	ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn,
-	const 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.
@@ -810,7 +875,7 @@
  * \retval NULL on error.
  */
 struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags);
-struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, char *file, int line, const char *funcname, int ref_debug);
+struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *funcname, int ref_debug);
 #if defined(REF_DEBUG)
 
 #define ao2_t_container_clone(orig, flags, tag)	__ao2_container_clone_debug(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
@@ -843,6 +908,7 @@
  *
  * \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)
  * \param tag used for debugging.
  *
  * \retval NULL on errors.
@@ -860,20 +926,20 @@
 #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__)
+#define ao2_t_link_flags(container, obj, flags, tag)	__ao2_link_debug((container), (obj), (flags), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_link_flags(container, obj, flags)			__ao2_link_debug((container), (obj), (flags), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 #else
 
 #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)
+#define ao2_t_link_flags(container, obj, flags, tag)	__ao2_link((container), (obj), (flags))
+#define ao2_link_flags(container, obj, flags)			__ao2_link((container), (obj), (flags))
 
 #endif
 
-void *__ao2_link_debug(struct ao2_container *c, void *new_obj, int flags, const 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);
 
 /*!
@@ -881,6 +947,7 @@
  *
  * \param container The container to operate on.
  * \param obj The object to unlink.
+ * \param flags search_flags to control unlinking the object.  (OBJ_NOLOCK)
  * \param tag used for debugging.
  *
  * \retval NULL, always
@@ -898,20 +965,20 @@
 #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__)
+#define ao2_t_unlink_flags(container, obj, flags, tag)	__ao2_unlink_debug((container), (obj), (flags), (tag),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_unlink_flags(container, obj, flags)			__ao2_unlink_debug((container), (obj), (flags), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 #else
 
 #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)
+#define ao2_t_unlink_flags(container, obj, flags, tag)	__ao2_unlink((container), (obj), (flags))
+#define ao2_unlink_flags(container, obj, flags)			__ao2_unlink((container), (obj), (flags))
 
 #endif
 
-void *__ao2_unlink_debug(struct ao2_container *c, void *obj, int flags, const 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);
 
 
@@ -1010,7 +1077,7 @@
 #endif
 
 void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_fn *cb_fn, void *arg, const char *tag, char *file, int line,
+	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);
 
@@ -1048,7 +1115,7 @@
 #endif
 
 void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
-	ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, char *file,
+	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);
@@ -1073,7 +1140,7 @@
 #endif
 
 void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
-	const char *tag, char *file, int line, const char *funcname);
+	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
@@ -1176,8 +1243,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
@@ -1234,7 +1311,7 @@
 
 #endif
 
-void *__ao2_iterator_next_debug(struct ao2_iterator *a, const 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: trunk/include/asterisk/lock.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/lock.h?view=diff&rev=357272&r1=357271&r2=357272
==============================================================================
--- trunk/include/asterisk/lock.h (original)
+++ trunk/include/asterisk/lock.h Tue Feb 28 12:15:34 2012
@@ -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: trunk/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/astobj2.c?view=diff&rev=357272&r1=357271&r2=357272
==============================================================================
--- trunk/main/astobj2.c (original)
+++ trunk/main/astobj2.c Tue Feb 28 12:15:34 2012
@@ -34,20 +34,19 @@
 
 /*!
  * 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;
+	/*! The 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;
@@ -64,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 {
@@ -102,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
  *
@@ -119,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;
@@ -137,77 +162,343 @@
  */
 #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,
-				   const char *tag, char *file, int line, const char *funcname);
-static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_entry **q);
-
-int __ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
-{
-	struct astobj2 *p = INTERNAL_OBJ(user_data);
-
-	if (p == NULL)
+int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
+{
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_lock *obj_mutex;
+	struct astobj2_rwlock *obj_rwlock;
+	int res = 0;
+
+	if (obj == NULL) {
 		return -1;
-
-#ifdef AO2_DEBUG
-	ast_atomic_fetchadd_int(&ao2.total_locked, 1);
-#endif
-
-	return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock);
+	}
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
+		res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
+#ifdef AO2_DEBUG
+		if (!res) {
+			ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+		}
+#endif
+		break;
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
+		switch (lock_how) {
+		case AO2_LOCK_REQ_MUTEX:
+		case AO2_LOCK_REQ_WRLOCK:
+			res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
+			if (!res) {
+				ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
+#ifdef AO2_DEBUG
+				ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+			}
+			break;
+		case AO2_LOCK_REQ_RDLOCK:
+			res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
+			if (!res) {
+				ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
+#ifdef AO2_DEBUG
+				ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+			}
+			break;
+		}
+		break;
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+		/* The ao2 object has no lock. */
+		break;
+	default:
+		ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
+			user_data);
+		return -1;
+	}
+
+	return res;
 }
 
 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
 {
-	struct astobj2 *p = INTERNAL_OBJ(user_data);
-
-	if (p == NULL)
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_lock *obj_mutex;
+	struct astobj2_rwlock *obj_rwlock;
+	int res = 0;
+	int current_value;
+
+	if (obj == NULL) {
 		return -1;
-
-#ifdef AO2_DEBUG
-	ast_atomic_fetchadd_int(&ao2.total_locked, -1);
-#endif
-
-	return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock);
-}
-
-int __ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
-{
-	struct astobj2 *p = INTERNAL_OBJ(user_data);
+	}
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
+		res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
+#ifdef AO2_DEBUG
+		if (!res) {
+			ast_atomic_fetchadd_int(&ao2.total_locked, -1);
+		}
+#endif
+		break;
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
+
+		current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
+		if (current_value < 0) {
+			/* It was a WRLOCK that we are unlocking.  Fix the count. */
+			ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
+		}
+		res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
+#ifdef AO2_DEBUG
+		if (!res) {
+			ast_atomic_fetchadd_int(&ao2.total_locked, -1);
+		}
+#endif
+		break;
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+		/* The ao2 object has no lock. */
+		break;
+	default:
+		ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
+			user_data);
+		res = -1;
+		break;
+	}
+	return res;
+}
+
+int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
+{
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_lock *obj_mutex;
+	struct astobj2_rwlock *obj_rwlock;
+	int res = 0;
+
+	if (obj == NULL) {
+		return -1;
+	}
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
+		res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
+#ifdef AO2_DEBUG
+		if (!res) {
+			ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+		}
+#endif
+		break;
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
+		switch (lock_how) {
+		case AO2_LOCK_REQ_MUTEX:
+		case AO2_LOCK_REQ_WRLOCK:
+			res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
+			if (!res) {
+				ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
+#ifdef AO2_DEBUG
+				ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+			}
+			break;
+		case AO2_LOCK_REQ_RDLOCK:
+			res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
+			if (!res) {
+				ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
+#ifdef AO2_DEBUG
+				ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+			}
+			break;
+		}
+		break;
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+		/* The ao2 object has no lock. */
+		return 0;
+	default:
+		ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
+			user_data);
+		return -1;
+	}
+
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Adjust an object's lock to the requested level.
+ *
+ * \param user_data An ao2 object to adjust lock level.
+ * \param lock_how What level to adjust lock.
+ * \param keep_stronger TRUE if keep original lock level if it is stronger.
+ *
+ * \pre The ao2 object is already locked.
+ *
+ * \details
+ * An ao2 object with a RWLOCK will have its lock level adjusted
+ * to the specified level if it is not already there.  An ao2
+ * object with a different type of lock is not affected.
+ *
+ * \return Original lock level.
+ */
+static enum ao2_lock_req adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
+{
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_rwlock *obj_rwlock;
+	enum ao2_lock_req orig_lock;
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
+		if (obj_rwlock->rwlock.num_lockers < 0) {
+			orig_lock = AO2_LOCK_REQ_WRLOCK;
+		} else {
+			orig_lock = AO2_LOCK_REQ_RDLOCK;
+		}
+		switch (lock_how) {
+		case AO2_LOCK_REQ_MUTEX:
+			lock_how = AO2_LOCK_REQ_WRLOCK;
+			/* Fall through */
+		case AO2_LOCK_REQ_WRLOCK:
+			if (lock_how != orig_lock) {
+				/* Switch from read lock to write lock. */
+				ao2_unlock(user_data);
+				ao2_wrlock(user_data);
+			}
+			break;
+		case AO2_LOCK_REQ_RDLOCK:
+			if (!keep_stronger && lock_how != orig_lock) {
+				/* Switch from write lock to read lock. */
+				ao2_unlock(user_data);
+				ao2_rdlock(user_data);
+			}
+			break;
+		}
+		break;
+	default:
+		ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
+		/* Fall through */
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		orig_lock = AO2_LOCK_REQ_MUTEX;
+		break;
+	}
+
+	return orig_lock;
+}
+
+void *ao2_object_get_lockaddr(void *user_data)
+{
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_lock *obj_mutex;
+
+	if (obj == NULL) {
+		return NULL;
+	}
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
+		return &obj_mutex->mutex.lock;
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
+static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *funcname)
+{
+	struct astobj2 *obj = INTERNAL_OBJ(user_data);
+	struct astobj2_lock *obj_mutex;
+	struct astobj2_rwlock *obj_rwlock;
+	int current_value;
 	int ret;
 
-	if (p == NULL)
+	if (obj == NULL) {
 		return -1;
-	ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
-
-#ifdef AO2_DEBUG
-	if (!ret)
-		ast_atomic_fetchadd_int(&ao2.total_locked, 1);
-#endif
+	}
+
+	/* if delta is 0, just return the refcount */
+	if (delta == 0) {
+		return obj->priv_data.ref_counter;
+	}
+
+	/* we modify with an atomic operation the reference counter */
+	ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
+	current_value = ret + delta;
+
+#ifdef AO2_DEBUG
+	ast_atomic_fetchadd_int(&ao2.total_refs, delta);
+#endif
+
+	if (0 < current_value) {
+		/* The object still lives. */
+		return ret;
+	}
+
+	/* this case must never happen */
+	if (current_value < 0) {
+		ast_log(__LOG_ERROR, file, line, funcname,
+			"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
+	}
+
+	/* last reference, destroy the object */
+	if (obj->priv_data.destructor_fn != NULL) {
+		obj->priv_data.destructor_fn(user_data);
+	}
+
+#ifdef AO2_DEBUG
+	ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
+	ast_atomic_fetchadd_int(&ao2.total_objects, -1);
+#endif
+
+	switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
+		obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
+		ast_mutex_destroy(&obj_mutex->mutex.lock);
+
+		/*
+		 * For safety, zero-out the astobj2_lock header and also the
+		 * first word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj_mutex, '\0', sizeof(*obj_mutex) + sizeof(void *) );
+		ast_free(obj_mutex);
+		break;
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+		obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
+		ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
+
+		/*
+		 * For safety, zero-out the astobj2_rwlock header and also the
+		 * first word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj_rwlock, '\0', sizeof(*obj_rwlock) + sizeof(void *) );
+		ast_free(obj_rwlock);
+		break;
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+		/*
+		 * For safety, zero-out the astobj2 header and also the first
+		 * word of the user-data, which we make sure is always
+		 * allocated.
+		 */
+		memset(obj, '\0', sizeof(*obj) + sizeof(void *) );
+		ast_free(obj);
+		break;
+	default:
+		ast_log(__LOG_ERROR, file, line, funcname,
+			"Invalid lock option on ao2 object %p\n", user_data);
+		break;
+	}
+
 	return ret;
 }
 
-void *ao2_object_get_lockaddr(void *obj)
-{
-	struct astobj2 *p = INTERNAL_OBJ(obj);
-
-	if (p == NULL)
-		return NULL;
-
-	return &p->priv_data.lock;
-}
-
-/*
- * The argument is a pointer to the user portion.
- */
-
-
-int __ao2_ref_debug(void *user_data, const int delta, const char *tag, char *file, int line, const char *funcname)
+int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *funcname)
 {
 	struct astobj2 *obj = INTERNAL_OBJ(user_data);
 
@@ -229,90 +520,83 @@
 			fclose(refo);
 		}
 	}
-	return internal_ao2_ref(user_data, delta);
-}
-
-int __ao2_ref(void *user_data, const int delta)
+	return internal_ao2_ref(user_data, delta, file, line, funcname);
+}
+
+int __ao2_ref(void *user_data, int delta)
 {
 	struct astobj2 *obj = INTERNAL_OBJ(user_data);
 
 	if (obj == NULL)
 		return -1;
 
-	return internal_ao2_ref(user_data, delta);
-}
-
-static int internal_ao2_ref(void *user_data, const int delta)
-{
-	struct astobj2 *obj = INTERNAL_OBJ(user_data);
-	int current_value;
-	int ret;
-
-	if (obj == NULL)
-		return -1;
-
-	/* if delta is 0, just return the refcount */
-	if (delta == 0)
-		return (obj->priv_data.ref_counter);
-
-	/* we modify with an atomic operation the reference counter */
-	ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
-	current_value = ret + delta;
-
-#ifdef AO2_DEBUG
-	ast_atomic_fetchadd_int(&ao2.total_refs, delta);
-#endif
-
-	/* this case must never happen */
-	if (current_value < 0)
-		ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
-
-	if (current_value <= 0) { /* last reference, destroy the object */
-		if (obj->priv_data.destructor_fn != NULL) {
-			obj->priv_data.destructor_fn(user_data);
-		}
-
-		ast_mutex_destroy(&obj->priv_data.lock);
-#ifdef AO2_DEBUG
-		ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
-		ast_atomic_fetchadd_int(&ao2.total_objects, -1);
-#endif
-		/* for safety, zero-out the astobj2 header and also the
-		 * first word of the user-data, which we make sure is always
-		 * allocated. */
-		memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
-		ast_free(obj);
-	}
-
-	return ret;
-}
-
-/*
- * We always alloc at least the size of a void *,
- * for debugging purposes.
- */
-static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname)
+	return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
+}
+
+static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *funcname)
 {
 	/* allocation */
 	struct astobj2 *obj;
-
-	if (data_size < sizeof(void *))
+	struct astobj2_lock *obj_mutex;
+	struct astobj2_rwlock *obj_rwlock;
+
+	if (data_size < sizeof(void *)) {
+		/*
+		 * We always alloc at least the size of a void *,
+		 * for debugging purposes.
+		 */
 		data_size = sizeof(void *);
-
+	}
+
+	switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
+	case AO2_ALLOC_OPT_LOCK_MUTEX:
 #if defined(__AST_DEBUG_MALLOC)
-	obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
+		obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, funcname);
 #else
-	obj = ast_calloc(1, sizeof(*obj) + data_size);
-#endif
-
-	if (obj == NULL)
-		return NULL;
-
-	ast_mutex_init(&obj->priv_data.lock);
-	obj->priv_data.magic = AO2_MAGIC;
-	obj->priv_data.data_size = data_size;
+		obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size);
+#endif
+		if (obj_mutex == NULL) {
+			return NULL;
+		}
+
+		ast_mutex_init(&obj_mutex->mutex.lock);
+		obj = (struct astobj2 *) &obj_mutex->priv_data;
+		break;
+	case AO2_ALLOC_OPT_LOCK_RWLOCK:
+#if defined(__AST_DEBUG_MALLOC)
+		obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, funcname);
+#else
+		obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size);
+#endif
+		if (obj_rwlock == NULL) {
+			return NULL;
+		}
+
+		ast_rwlock_init(&obj_rwlock->rwlock.lock);
+		obj = (struct astobj2 *) &obj_rwlock->priv_data;
+		break;
+	case AO2_ALLOC_OPT_LOCK_NOLOCK:
+#if defined(__AST_DEBUG_MALLOC)
+		obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
+#else
+		obj = ast_calloc(1, sizeof(*obj) + data_size);
+#endif
+		if (obj == NULL) {
+			return NULL;
+		}
+		break;
+	default:
+		/* Invalid option value. */
+		ast_log(__LOG_DEBUG, file, line, funcname, "Invalid lock option requested\n");
+		return NULL;
+	}
+
+	/* Initialize common ao2 values. */
 	obj->priv_data.ref_counter = 1;
 	obj->priv_data.destructor_fn = destructor_fn;	/* can be NULL */
+	obj->priv_data.data_size = data_size;
+	obj->priv_data.options = options;
+	obj->priv_data.magic = AO2_MAGIC;
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_objects, 1);
@@ -324,14 +608,14 @@
 	return EXTERNAL_OBJ(obj);
 }
 
-void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, const char *tag,
-			const char *file, int line, const char *funcname, int ref_debug)
+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)
 {
 	/* allocation */
 	void *obj;
 	FILE *refo;
 
-	if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) {
+	if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, funcname)) == NULL) {
 		return NULL;
 	}
 
@@ -344,9 +628,9 @@
 	return obj;
 }
 
-void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
-{
-	return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);

[... 1086 lines stripped ...]



More information about the asterisk-commits mailing list