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/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@357272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
certified/11.2
Richard Mudgett 13 years ago
parent bd7e9dae66
commit 2e834f7d36

@ -390,12 +390,24 @@ murf
*/
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 @@ typedef void (*ao2_destructor_fn)(void *);
#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,19 +503,31 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn);
#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.
*
* \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 @@ int __ao2_unlock(void *a, const char *file, const char *func, int line, const ch
* \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 @@ enum search_flags {
*/
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 @@ struct ao2_container;
* 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 @@ struct ao2_container;
#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 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
* \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 @@ struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, en
*
* \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 @@ struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, en
#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 @@ void *__ao2_link(struct ao2_container *c, void *newobj, int flags);
*
* \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 @@ void *__ao2_link(struct ao2_container *c, void *newobj, int flags);
#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 @@ void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
#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 @@ void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callb
#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 @@ void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
#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 @@ struct ao2_iterator {
* 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 @@ void ao2_iterator_destroy(struct ao2_iterator *i);
#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 */

@ -352,7 +352,7 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in
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)

File diff suppressed because it is too large Load Diff

@ -41,22 +41,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
#define FORMAT_CONFIG "codecs.conf"
/*! This is the container for all the format attribute interfaces.
* An ao2 container was chosen for fast lookup. */
/*!
* \brief Container for all the format attribute interfaces.
* \note This container uses RWLOCKs instead of MUTEX locks. .
* \note An ao2 container was chosen for fast lookup.
*/
static struct ao2_container *interfaces;
/*! This is the lock used to protect the interfaces container. Yes, ao2_containers
* do have their own locking, but we need the capability of performing read/write
* locks on this specific container. */
static ast_rwlock_t ilock;
/*! a wrapper is used put interfaces into the ao2 container. */
struct interface_ao2_wrapper {
enum ast_format_id id;
const struct ast_format_attr_interface *interface;
/*! a read write lock must be used to protect the wrapper instead
* of the ao2 lock. */
ast_rwlock_t wraplock;
};
/*! \brief Format List container, This container is never directly accessed outside
@ -84,12 +79,6 @@ static int interface_hash_cb(const void *obj, const int flags)
return wrapper->id;
}
static void interface_destroy_cb(void *obj)
{
struct interface_ao2_wrapper *wrapper = obj;
ast_rwlock_destroy(&wrapper->wraplock);
}
void ast_format_copy(struct ast_format *dst, const struct ast_format *src)
{
memcpy(dst, src, sizeof(struct ast_format));
@ -107,16 +96,11 @@ int ast_format_get_video_mark(const struct ast_format *format)
static struct interface_ao2_wrapper *find_interface(const struct ast_format *format)
{
struct interface_ao2_wrapper *wrapper;
struct interface_ao2_wrapper tmp_wrapper = {
.id = format->id,
};
ast_rwlock_rdlock(&ilock);
wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK));
ast_rwlock_unlock(&ilock);
return wrapper;
return ao2_find(interfaces, &tmp_wrapper, OBJ_POINTER);
}
static int has_interface(const struct ast_format *format)
@ -143,16 +127,16 @@ static int format_set_helper(struct ast_format *format, va_list ap)
return -1;
}
ast_rwlock_rdlock(&wrapper->wraplock);
ao2_rdlock(wrapper);
if (!wrapper->interface || !wrapper->interface->format_attr_set) {
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return -1;
}
wrapper->interface->format_attr_set(&format->fattr, ap);
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return 0;
@ -207,12 +191,12 @@ static int format_isset_helper(const struct ast_format *format, va_list ap)
return -1;
}
ast_rwlock_rdlock(&wrapper->wraplock);
ao2_rdlock(wrapper);
if (!wrapper->interface ||
!wrapper->interface->format_attr_set ||
!wrapper->interface->format_attr_cmp) {
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return -1;
}
@ -228,7 +212,7 @@ static int format_isset_helper(const struct ast_format *format, va_list ap)
res = (res == AST_FORMAT_CMP_NOT_EQUAL) ? -1 : 0;
}
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return res;
@ -249,21 +233,22 @@ int ast_format_get_value(const struct ast_format *format, int key, void *value)
{
int res = 0;
struct interface_ao2_wrapper *wrapper;
if (!(wrapper = find_interface(format))) {
return -1;
}
ast_rwlock_rdlock(&wrapper->wraplock);
ao2_rdlock(wrapper);
if (!wrapper->interface ||
!wrapper->interface->format_attr_get_val) {
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return -1;
}
res = wrapper->interface->format_attr_get_val(&format->fattr, key, value);
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return res;
@ -281,16 +266,16 @@ static enum ast_format_cmp_res format_cmp_helper(const struct ast_format *format
return res;
}
ast_rwlock_rdlock(&wrapper->wraplock);
ao2_rdlock(wrapper);
if (!wrapper->interface || !wrapper->interface->format_attr_cmp) {
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return res;
}
res = wrapper->interface->format_attr_cmp(&format1->fattr, &format2->fattr);
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
return res;
@ -318,11 +303,11 @@ static int format_joint_helper(const struct ast_format *format1, const struct as
return res;
}
ast_rwlock_rdlock(&wrapper->wraplock);
ao2_rdlock(wrapper);
if (wrapper->interface && wrapper->interface->format_attr_get_joint) {
res = wrapper->interface->format_attr_get_joint(&format1->fattr, &format2->fattr, &result->fattr);
}
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);
@ -1066,21 +1051,13 @@ init_list_cleanup:
int ast_format_attr_init(void)
{
ast_cli_register_multiple(my_clis, ARRAY_LEN(my_clis));
if (ast_rwlock_init(&ilock)) {
return -1;
}
if (!(interfaces = ao2_container_alloc(283, interface_hash_cb, interface_cmp_cb))) {
goto init_cleanup;
interfaces = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_RWLOCK,
283, interface_hash_cb, interface_cmp_cb);
if (!interfaces) {
return -1;
}
return 0;
init_cleanup:
ast_rwlock_destroy(&ilock);
if (interfaces) {
ao2_ref(interfaces, -1);
}
return -1;
}
static int custom_celt_format(struct ast_format_list *entry, unsigned int maxbitrate, unsigned int framesize)
@ -1310,28 +1287,28 @@ int ast_format_attr_reg_interface(const struct ast_format_attr_interface *interf
* anticipation of adding a new interface and to prevent a
* duplicate from sneaking in between the check and add.
*/
ast_rwlock_wrlock(&ilock);
ao2_wrlock(interfaces);
/* check for duplicates first*/
if ((wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_NOLOCK)))) {
ast_rwlock_unlock(&ilock);
ao2_unlock(interfaces);
ast_log(LOG_WARNING, "Can not register attribute interface for format id %d, interface already exists.\n", interface->id);
ao2_ref(wrapper, -1);
return -1;
}
if (!(wrapper = ao2_alloc(sizeof(*wrapper), interface_destroy_cb))) {
ast_rwlock_unlock(&ilock);
wrapper = ao2_alloc_options(sizeof(*wrapper), NULL, AO2_ALLOC_OPT_LOCK_RWLOCK);
if (!wrapper) {
ao2_unlock(interfaces);
return -1;
}
wrapper->interface = interface;
wrapper->id = interface->id;
ast_rwlock_init(&wrapper->wraplock);
/* The write lock is already held. */
ao2_link_nolock(interfaces, wrapper);
ast_rwlock_unlock(&ilock);
ao2_link_flags(interfaces, wrapper, OBJ_NOLOCK);
ao2_unlock(interfaces);
ao2_ref(wrapper, -1);
@ -1359,17 +1336,13 @@ int ast_format_attr_unreg_interface(const struct ast_format_attr_interface *inte
.id = interface->id,
};
/* use the write lock whenever the interface container is modified */
ast_rwlock_wrlock(&ilock);
if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK | OBJ_NOLOCK)))) {
ast_rwlock_unlock(&ilock);
if (!(wrapper = ao2_find(interfaces, &tmp_wrapper, (OBJ_POINTER | OBJ_UNLINK)))) {
return -1;
}
ast_rwlock_unlock(&ilock);
ast_rwlock_wrlock(&wrapper->wraplock);
ao2_wrlock(wrapper);
wrapper->interface = NULL;
ast_rwlock_unlock(&wrapper->wraplock);
ao2_unlock(wrapper);
ao2_ref(wrapper, -1);

@ -39,6 +39,7 @@ struct ast_format_cap {
/* The capabilities structure is just an ao2 container of ast_formats */
struct ao2_container *formats;
struct ao2_iterator it;
/*! TRUE if the formats container created without a lock. */
int nolock;
};
@ -69,8 +70,11 @@ static struct ast_format_cap *cap_alloc_helper(int nolock)
if (!cap) {
return NULL;
}
cap->nolock = nolock ? OBJ_NOLOCK : 0;
if (!(cap->formats = ao2_container_alloc(283, hash_cb, cmp_cb))) {
cap->nolock = nolock;
cap->formats = ao2_container_alloc_options(
nolock ? AO2_ALLOC_OPT_LOCK_NOLOCK : AO2_ALLOC_OPT_LOCK_MUTEX,
283, hash_cb, cmp_cb);
if (!cap->formats) {
ast_free(cap);
return NULL;
}
@ -109,11 +113,7 @@ void ast_format_cap_add(struct ast_format_cap *cap, const struct ast_format *for
return;
}
ast_format_copy(fnew, format);
if (cap->nolock) {
ao2_link_nolock(cap->formats, fnew);
} else {
ao2_link(cap->formats, fnew);
}
ao2_link(cap->formats, fnew);
ao2_ref(fnew, -1);
}
@ -157,7 +157,7 @@ static int append_cb(void *obj, void *arg, int flag)
void ast_format_cap_append(struct ast_format_cap *dst, const struct ast_format_cap *src)
{
ao2_callback(src->formats, OBJ_NODATA | src->nolock, append_cb, dst);
ao2_callback(src->formats, OBJ_NODATA, append_cb, dst);
}
static int copy_cb(void *obj, void *arg, int flag)
@ -172,7 +172,7 @@ static int copy_cb(void *obj, void *arg, int flag)
void ast_format_cap_copy(struct ast_format_cap *dst, const struct ast_format_cap *src)
{
ast_format_cap_remove_all(dst);
ao2_callback(src->formats, OBJ_NODATA | src->nolock, copy_cb, dst);
ao2_callback(src->formats, OBJ_NODATA, copy_cb, dst);
}
struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
@ -186,7 +186,7 @@ struct ast_format_cap *ast_format_cap_dup(const struct ast_format_cap *cap)
if (!dst) {
return NULL;
}
ao2_callback(cap->formats, OBJ_NODATA | cap->nolock, copy_cb, dst);
ao2_callback(cap->formats, OBJ_NODATA, copy_cb, dst);
return dst;
}
@ -209,8 +209,8 @@ static int find_exact_cb(void *obj, void *arg, int flag)
int ast_format_cap_remove(struct ast_format_cap *cap, struct ast_format *format)
{
struct ast_format *fremove;
fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK | cap->nolock, find_exact_cb, format);
fremove = ao2_callback(cap->formats, OBJ_POINTER | OBJ_UNLINK, find_exact_cb, format);
if (fremove) {
ao2_ref(fremove, -1);
return 0;
@ -249,7 +249,7 @@ int ast_format_cap_remove_byid(struct ast_format_cap *cap, enum ast_format_id id
};
ao2_callback(cap->formats,
OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK,
OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
multiple_by_id_cb,
&data);
@ -271,14 +271,14 @@ static int multiple_by_type_cb(void *obj, void *arg, int flag)
void ast_format_cap_remove_bytype(struct ast_format_cap *cap, enum ast_format_type type)
{
ao2_callback(cap->formats,
OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE | cap->nolock,
OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
multiple_by_type_cb,
&type);
}
void ast_format_cap_remove_all(struct ast_format_cap *cap)
{
ao2_callback(cap->formats, OBJ_NODATA | cap->nolock | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
ao2_callback(cap->formats, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, NULL, NULL);
}
void ast_format_cap_set(struct ast_format_cap *cap, struct ast_format *format)
@ -291,8 +291,8 @@ int ast_format_cap_get_compatible_format(const struct ast_format_cap *cap, const
{
struct ast_format *f;
struct ast_format_cap *tmp_cap = (struct ast_format_cap *) cap;
f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);
f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
if (f) {
ast_format_copy(result, f);
ao2_ref(f, -1);
@ -310,7 +310,8 @@ int ast_format_cap_iscompatible(const struct ast_format_cap *cap, const struct a
if (!tmp_cap) {
return 0;
}
f = ao2_find(tmp_cap->formats, (struct ast_format *) format, OBJ_POINTER | tmp_cap->nolock);
f = ao2_find(tmp_cap->formats, format, OBJ_POINTER);
if (f) {
ao2_ref(f, -1);
return 1;
@ -345,7 +346,7 @@ int ast_format_cap_best_byid(const struct ast_format_cap *cap, enum ast_format_i
ast_format_clear(result);
ao2_callback(cap->formats,
OBJ_MULTIPLE | OBJ_NODATA | cap->nolock,
OBJ_MULTIPLE | OBJ_NODATA,
find_best_byid_cb,
&data);
return result->id ? 1 : 0;
@ -389,11 +390,11 @@ int ast_format_cap_has_joint(const struct ast_format_cap *cap1, const struct ast
.joint_cap = NULL,
};
it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap1->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
data.format = tmp;
ao2_callback(cap2->formats,
OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
OBJ_MULTIPLE | OBJ_NODATA,
find_joint_cb,
&data);
ao2_ref(tmp, -1);
@ -412,7 +413,7 @@ int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast
return 0; /* if they are not the same size, they are not identical */
}
it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap1->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
if (!ast_format_cap_iscompatible(cap2, tmp)) {
ao2_ref(tmp, -1);
@ -439,11 +440,11 @@ struct ast_format_cap *ast_format_cap_joint(const struct ast_format_cap *cap1, c
return NULL;
}
it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap1->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
data.format = tmp;
ao2_callback(cap2->formats,
OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
OBJ_MULTIPLE | OBJ_NODATA,
find_joint_cb,
&data);
ao2_ref(tmp, -1);
@ -469,11 +470,11 @@ static int joint_copy_helper(const struct ast_format_cap *cap1, const struct ast
if (!append) {
ast_format_cap_remove_all(result);
}
it = ao2_iterator_init(cap1->formats, cap1->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap1->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
data.format = tmp;
ao2_callback(cap2->formats,
OBJ_MULTIPLE | OBJ_NODATA | cap2->nolock,
OBJ_MULTIPLE | OBJ_NODATA,
find_joint_cb,
&data);
ao2_ref(tmp, -1);
@ -505,7 +506,7 @@ struct ast_format_cap *ast_format_cap_get_type(const struct ast_format_cap *cap,
/* for each format in cap1, see if that format is
* compatible with cap2. If so copy it to the result */
it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
if (AST_FORMAT_GET_TYPE(tmp->id) == ftype) {
/* copy format */
@ -529,7 +530,7 @@ int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_ty
struct ao2_iterator it;
struct ast_format *tmp;
it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
if (AST_FORMAT_GET_TYPE(tmp->id) == type) {
ao2_ref(tmp, -1);
@ -545,18 +546,16 @@ int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_format_ty
void ast_format_cap_iter_start(struct ast_format_cap *cap)
{
if (!cap->nolock) {
ao2_lock(cap->formats);
}
cap->it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
/* We can unconditionally lock even if the container has no lock. */
ao2_lock(cap->formats);
cap->it = ao2_iterator_init(cap->formats, AO2_ITERATOR_DONTLOCK);
}
void ast_format_cap_iter_end(struct ast_format_cap *cap)
{
ao2_iterator_destroy(&cap->it);
if (!cap->nolock) {
ao2_unlock(cap->formats);
}
/* We can unconditionally unlock even if the container has no lock. */
ao2_unlock(cap->formats);
}
int ast_format_cap_iter_next(struct ast_format_cap *cap, struct ast_format *format)
@ -614,7 +613,7 @@ uint64_t ast_format_cap_to_old_bitfield(const struct ast_format_cap *cap)
struct ao2_iterator it;
struct ast_format *tmp;
it = ao2_iterator_init(cap->formats, cap->nolock ? AO2_ITERATOR_DONTLOCK : 0);
it = ao2_iterator_init(cap->formats, 0);
while ((tmp = ao2_iterator_next(&it))) {
res |= ast_format_to_old_bitfield(tmp);
ao2_ref(tmp, -1);

Loading…
Cancel
Save