diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-11-02 04:12:36 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-11-02 04:12:36 +0000 |
commit | 629a5fc39b1ad8bc638106c1f23537e797b5bedc (patch) | |
tree | fc9d6f9fee325d65f5ac96235b6589850f41d3bc /include | |
parent | a84cff117d1f862a6b345f87d0ba1f158e5feecd (diff) |
vector: Update API to be more flexible.
Made the vector macro API be more like linked lists.
1) Added a name parameter to ast_vector() to name the vector struct.
2) Made the API take a pointer to the vector struct instead of the struct
itself.
3) Added an element cleanup macro/function parameter when removing an
element from the vector for ast_vector_remove_cmp_unordered() and
ast_vector_remove_elem_unordered().
4) Added ast_vector_get_addr() in case the vector element is not a simple
pointer.
* Converted an inline vector usage in stasis_message_router to use the
vector API. It needed the API improvements so it could be converted.
* Fixed topic reference leak in router_dtor() when the
stasis_message_router is destroyed.
* Fixed deadlock potential in stasis_forward_all() and
stasis_forward_cancel(). Locking two topics at the same time requires
deadlock avoidance.
* Made internal_stasis_subscribe() tolerant of a NULL topic.
* Made stasis_message_router_add(),
stasis_message_router_add_cache_update(), stasis_message_router_remove(),
and stasis_message_router_remove_cache_update() tolerant of a NULL
message_type.
* Promoted a LOG_DEBUG message to LOG_ERROR as intended in
dispatch_message().
Review: https://reviewboard.asterisk.org/r/2903/
........
Merged revisions 402429 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402430 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'include')
-rw-r--r-- | include/asterisk/lock.h | 31 | ||||
-rw-r--r-- | include/asterisk/vector.h | 134 |
2 files changed, 115 insertions, 50 deletions
diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index d76a8d185..7741654a0 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -339,6 +339,28 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in * used during deadlock avoidance, to preserve the original location where * a lock was originally acquired. */ +#define AO2_DEADLOCK_AVOIDANCE(obj) \ + do { \ + char __filename[80], __func[80], __mutex_name[80]; \ + int __lineno; \ + int __res = ast_find_lock_info(ao2_object_get_lockaddr(obj), __filename, sizeof(__filename), &__lineno, __func, sizeof(__func), __mutex_name, sizeof(__mutex_name)); \ + int __res2 = ao2_unlock(obj); \ + usleep(1); \ + if (__res < 0) { /* Could happen if the ao2 object does not have a mutex. */ \ + if (__res2) { \ + ast_log(LOG_WARNING, "Could not unlock ao2 object '%s': %s and no lock info found! I will NOT try to relock.\n", #obj, strerror(__res2)); \ + } else { \ + ao2_lock(obj); \ + } \ + } else { \ + if (__res2) { \ + ast_log(LOG_WARNING, "Could not unlock ao2 object '%s': %s. {{{Originally locked at %s line %d: (%s) '%s'}}} I will NOT try to relock.\n", #obj, strerror(__res2), __filename, __lineno, __func, __mutex_name); \ + } else { \ + __ao2_lock(obj, AO2_LOCK_REQ_MUTEX, __filename, __func, __lineno, __mutex_name); \ + } \ + } \ + } while (0) + #define CHANNEL_DEADLOCK_AVOIDANCE(chan) \ do { \ char __filename[80], __func[80], __mutex_name[80]; \ @@ -493,12 +515,17 @@ static inline void delete_reentrancy_cs(struct ast_lock_track **plt) #else /* !DEBUG_THREADS */ -#define CHANNEL_DEADLOCK_AVOIDANCE(chan) \ +#define AO2_DEADLOCK_AVOIDANCE(obj) \ + ao2_unlock(obj); \ + usleep(1); \ + ao2_lock(obj); + +#define CHANNEL_DEADLOCK_AVOIDANCE(chan) \ ast_channel_unlock(chan); \ usleep(1); \ ast_channel_lock(chan); -#define DEADLOCK_AVOIDANCE(lock) \ +#define DEADLOCK_AVOIDANCE(lock) \ do { \ int __res; \ if (!(__res = ast_mutex_unlock(lock))) { \ diff --git a/include/asterisk/vector.h b/include/asterisk/vector.h index f5d3e9a14..4efc5ce4f 100644 --- a/include/asterisk/vector.h +++ b/include/asterisk/vector.h @@ -33,9 +33,14 @@ * \since 12 */ -/*! \brief Define a vector structure */ -#define ast_vector(type) \ - struct { \ +/*! + * \brief Define a vector structure + * + * \param name Optional vector struct name. + * \param type Vector element type. + */ +#define ast_vector(name, type) \ + struct name { \ type *elems; \ size_t max; \ size_t current; \ @@ -55,15 +60,15 @@ */ #define ast_vector_init(vec, size) ({ \ size_t __size = (size); \ - size_t alloc_size = __size * sizeof(*(vec).elems); \ - (vec).elems = alloc_size ? ast_malloc(alloc_size) : NULL; \ - (vec).current = 0; \ - if ((vec).elems) { \ - (vec).max = __size; \ + size_t alloc_size = __size * sizeof(*((vec)->elems)); \ + (vec)->elems = alloc_size ? ast_malloc(alloc_size) : NULL; \ + (vec)->current = 0; \ + if ((vec)->elems) { \ + (vec)->max = __size; \ } else { \ - (vec).max = 0; \ + (vec)->max = 0; \ } \ - alloc_size == 0 || (vec).elems != NULL ? 0 : -1; \ + (alloc_size == 0 || (vec)->elems != NULL) ? 0 : -1; \ }) /*! @@ -75,10 +80,10 @@ * \param vec Vector to deallocate. */ #define ast_vector_free(vec) do { \ - ast_free((vec).elems); \ - (vec).elems = NULL; \ - (vec).max = 0; \ - (vec).current = 0; \ + ast_free((vec)->elems); \ + (vec)->elems = NULL; \ + (vec)->max = 0; \ + (vec)->current = 0; \ } while (0) /*! @@ -90,25 +95,24 @@ * \return 0 on success. * \return Non-zero on failure. */ -#define ast_vector_append(vec, elem) ({ \ - int res = 0; \ - \ - if ((vec).current + 1 > (vec).max) { \ - size_t new_max = (vec).max ? 2 * (vec).max : 1; \ - typeof((vec).elems) new_elems = ast_realloc( \ - (vec).elems, new_max * sizeof(*new_elems)); \ - if (new_elems) { \ - (vec).elems = new_elems; \ - (vec).max = new_max; \ - } else { \ - res = -1; \ - } \ - } \ - \ - if (res == 0) { \ - (vec).elems[(vec).current++] = (elem); \ - } \ - res; \ +#define ast_vector_append(vec, elem) ({ \ + int res = 0; \ + do { \ + if ((vec)->current + 1 > (vec)->max) { \ + size_t new_max = (vec)->max ? 2 * (vec)->max : 1; \ + typeof((vec)->elems) new_elems = ast_realloc( \ + (vec)->elems, new_max * sizeof(*new_elems)); \ + if (new_elems) { \ + (vec)->elems = new_elems; \ + (vec)->max = new_max; \ + } else { \ + res = -1; \ + break; \ + } \ + } \ + (vec)->elems[(vec)->current++] = (elem); \ + } while (0); \ + res; \ }) /*! @@ -122,11 +126,11 @@ * \return The element that was removed. */ #define ast_vector_remove_unordered(vec, idx) ({ \ - typeof((vec).elems[0]) res; \ + typeof((vec)->elems[0]) res; \ size_t __idx = (idx); \ - ast_assert(__idx < (vec).current); \ - res = (vec).elems[__idx]; \ - (vec).elems[__idx] = (vec).elems[--(vec).current]; \ + ast_assert(__idx < (vec)->current); \ + res = (vec)->elems[__idx]; \ + (vec)->elems[__idx] = (vec)->elems[--(vec)->current]; \ res; \ }) @@ -137,15 +141,18 @@ * \param vec Vector to remove from. * \param value Value to pass into comparator. * \param cmp Comparator function/macros (called as \c cmp(elem, value)) + * \param cleanup How to cleanup a removed element macro/function. + * * \return 0 if element was removed. * \return Non-zero if element was not in the vector. */ -#define ast_vector_remove_cmp_unordered(vec, value, cmp) ({ \ +#define ast_vector_remove_cmp_unordered(vec, value, cmp, cleanup) ({ \ int res = -1; \ size_t idx; \ typeof(value) __value = (value); \ - for (idx = 0; idx < (vec).current; ++idx) { \ - if (cmp((vec).elems[idx], __value)) { \ + for (idx = 0; idx < (vec)->current; ++idx) { \ + if (cmp((vec)->elems[idx], __value)) { \ + cleanup((vec)->elems[idx]); \ ast_vector_remove_unordered((vec), idx); \ res = 0; \ break; \ @@ -154,20 +161,39 @@ res; \ }) -/*! \brief Default comparator for ast_vector_remove_elem_unordered() */ -#define AST_VECTOR_DEFAULT_CMP(a, b) ((a) == (b)) +/*! + * \brief Default comparator for ast_vector_remove_elem_unordered() + * + * \param elem Element to compare against + * \param value Value to compare with the vector element. + * + * \return 0 if element does not match. + * \return Non-zero if element matches. + */ +#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value) ((elem) == (value)) + +/*! + * \brief Vector element cleanup that does nothing. + * + * \param elem Element to cleanup + * + * \return Nothing + */ +#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem) /*! * \brief Remove an element from a vector. * * \param vec Vector to remove from. * \param elem Element to remove + * \param cleanup How to cleanup a removed element macro/function. + * * \return 0 if element was removed. * \return Non-zero if element was not in the vector. */ -#define ast_vector_remove_elem_unordered(vec, elem) ({ \ - ast_vector_remove_cmp_unordered((vec), (elem), \ - AST_VECTOR_DEFAULT_CMP); \ +#define ast_vector_remove_elem_unordered(vec, elem, cleanup) ({ \ + ast_vector_remove_cmp_unordered((vec), (elem), \ + AST_VECTOR_ELEM_DEFAULT_CMP, cleanup); \ }) /*! @@ -176,7 +202,19 @@ * \param vec Vector to query. * \return Number of elements in the vector. */ -#define ast_vector_size(vec) (vec).current +#define ast_vector_size(vec) (vec)->current + +/*! + * \brief Get an address of element in a vector. + * + * \param vec Vector to query. + * \param idx Index of the element to get address of. + */ +#define ast_vector_get_addr(vec, idx) ({ \ + size_t __idx = (idx); \ + ast_assert(__idx < (vec)->current); \ + &(vec)->elems[__idx]; \ +}) /*! * \brief Get an element from a vector. @@ -186,8 +224,8 @@ */ #define ast_vector_get(vec, idx) ({ \ size_t __idx = (idx); \ - ast_assert(__idx < (vec).current); \ - (vec).elems[__idx]; \ + ast_assert(__idx < (vec)->current); \ + (vec)->elems[__idx]; \ }) #endif /* _ASTERISK_VECTOR_H */ |