diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/asterisk/astobj2.h | 165 | ||||
-rw-r--r-- | include/asterisk/lock.h | 2 |
2 files changed, 122 insertions, 45 deletions
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 49b2a05f2..738b773cb 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -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 */ diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index fbcbecccf..943c7ffe6 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -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) |