Astobj2: Allow reference debugging to be enabled/disabled by config.

* The REF_DEBUG compiler flag no longer has any effect on code that uses
  Astobj2.  It is used to determine if reference debugging is enabled by
  default.  Reference debugging can be enabled or disabled in asterisk.conf.
* Caller information is provided in logger errors for ao2 bad magic numbers.
* Optimizes AO2 by merging internal functions with the public counterpart.
  This was possible now that we no longer require a dual ABI.

ASTERISK-24974 #close
Reported by: Corey Farrell

Change-Id: Icf3552721fe999365ba8a8cf00a965aa6b897cc1
This commit is contained in:
Corey Farrell 2015-04-17 03:16:59 -04:00
parent d7f4788341
commit 5c1d07baf0
26 changed files with 407 additions and 993 deletions

View File

@ -32,6 +32,9 @@ chan_dahdi:
Caller-ID detection.
Core:
- The REF_DEBUG compiler flag is now used to enable refdebug by default.
The setting can be overridden in asterisk.conf by setting refdebug in
the options category. No recompile is required to enable/disable it.
AMI:
- The 'ModuleCheck' Action's Version key will no longer show the module

View File

@ -1814,50 +1814,27 @@ static void queue_member_follower_removal(struct call_queue *queue, struct membe
ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
}
#ifdef REF_DEBUG
#define queue_ref(q) _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queue_unref(q) _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queue_t_ref(q, tag) _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queue_t_unref(q, tag) _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queues_t_link(c, q, tag) __ao2_link_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queues_t_unlink(c, q, tag) __ao2_unlink_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
{
__ao2_ref_debug(q, 1, tag, file, line, filename);
__ao2_ref(q, 1, tag, file, line, filename);
return q;
}
static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
{
if (q) {
__ao2_ref_debug(q, -1, tag, file, line, filename);
__ao2_ref(q, -1, tag, file, line, filename);
}
return NULL;
}
#else
#define queue_t_ref(q, tag) queue_ref(q)
#define queue_t_unref(q, tag) queue_unref(q)
#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
static inline struct call_queue *queue_ref(struct call_queue *q)
{
ao2_ref(q, 1);
return q;
}
static inline struct call_queue *queue_unref(struct call_queue *q)
{
if (q) {
ao2_ref(q, -1);
}
return NULL;
}
#endif
/*! \brief Set variables of queue */
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
{

View File

@ -5,7 +5,7 @@
<member name="DEBUG_THREADS" displayname="Enable Thread Debugging">
<support_level>core</support_level>
</member>
<member name="REF_DEBUG" displayname="Enable reference count debugging">
<member name="REF_DEBUG" displayname="Enable reference count debugging by default">
<support_level>extended</support_level>
</member>
<member name="AO2_DEBUG" displayname="Enable internal Astobj2 debugging">

View File

@ -13,6 +13,20 @@ END
TMP=`${GREP} -e "^MENUSELECT_CFLAGS" menuselect.makeopts | sed 's/MENUSELECT_CFLAGS\=//g' | sed 's/-D//g'`
for x in ${TMP}; do
echo "#define ${x} 1"
if test "${x}" = "DONT_OPTIMIZE" \
-o "${x}" = "BETTER_BACKTRACES" \
-o "${x}" = "LOTS_OF_SPANS" \
-o "${x}" = "BUILD_NATIVE" \
-o "${x}" = "REF_DEBUG" \
-o "${x}" = "AO2_DEBUG" \
-o "${x}" = "REBUILD_PARSERS" \
-o "${x}" = "RADIO_RELAX" \
-o "${x}" = "DEBUG_SCHEDULER" \
-o "${x}" = "DETECT_DEADLOCKS" \
-o "${x}" = "DUMP_SCHEDULER" ; then
# These aren't ABI affecting options, keep them out of AST_BUILDOPTS
continue
fi
if test "x${BUILDOPTS}" != "x" ; then
BUILDOPTS="${BUILDOPTS}, ${x}"
else

View File

@ -8599,9 +8599,9 @@ struct sip_pvt *__sip_alloc(ast_string_field callid, struct ast_sockaddr *addr,
{
struct sip_pvt *p;
p = __ao2_alloc_debug(sizeof(*p), sip_destroy_fn,
p = __ao2_alloc(sizeof(*p), sip_destroy_fn,
AO2_ALLOC_OPT_LOCK_MUTEX, "allocate a dialog(pvt) struct",
file, line, func, 1);
file, line, func);
if (!p) {
return NULL;
}
@ -9178,7 +9178,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
struct sip_pvt tmp_dialog = {
.callid = callid,
};
sip_pvt_ptr = __ao2_find_debug(dialogs, &tmp_dialog, OBJ_POINTER,
sip_pvt_ptr = __ao2_find(dialogs, &tmp_dialog, OBJ_POINTER,
"find_call in dialogs", file, line, func);
if (sip_pvt_ptr) { /* well, if we don't find it-- what IS in there? */
/* Found the call */
@ -9193,7 +9193,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
struct sip_pvt *fork_pvt = NULL;
struct match_req_args args = { 0, };
int found;
struct ao2_iterator *iterator = __ao2_callback_debug(dialogs,
struct ao2_iterator *iterator = __ao2_callback(dialogs,
OBJ_POINTER | OBJ_MULTIPLE,
dialog_find_multiple,
&tmp_dialog,
@ -9243,7 +9243,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
/* This is likely a forked Request that somehow resulted in us receiving multiple parts of the fork.
* RFC 3261 section 8.2.2.2, Indicate that we want to merge requests by sending a 482 response. */
transmit_response_using_temp(callid, addr, 1, intended_method, req, "482 (Loop Detected)");
__ao2_ref_debug(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search.",
__ao2_ref(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search.",
file, line, func);
ao2_iterator_destroy(iterator);
dialog_unref(fork_pvt, "unref fork_pvt");
@ -9255,7 +9255,7 @@ static struct sip_pvt *__find_call(struct sip_request *req, struct ast_sockaddr
/* fall through */
case SIP_REQ_NOT_MATCH:
default:
__ao2_ref_debug(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search",
__ao2_ref(sip_pvt_ptr, -1, "pvt did not match incoming SIP msg, unref from search",
file, line, func);
break;
}

View File

@ -14,6 +14,7 @@ astsbindir => /usr/sbin
[options]
;verbose = 3
;debug = 3
;refdebug = yes ; Enable reference count debug logging.
;alwaysfork = yes ; Same as -F at startup.
;nofork = yes ; Same as -f at startup.
;quiet = yes ; Same as -q at startup.

View File

@ -20,10 +20,8 @@ clean:
include $(ASTTOPDIR)/Makefile.rules
install:
if [ -n "$(findstring REF_DEBUG,$(MENUSELECT_CFLAGS))" ]; then \
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"; \
$(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"; \
fi
$(INSTALL) -d "$(DESTDIR)$(ASTDATADIR)/scripts"; \
$(INSTALL) -m 755 scripts/refcounter.py "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"; \
uninstall:
rm -f "$(DESTDIR)$(ASTDATADIR)/scripts/refcounter.py"

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
"""Process a ref debug log
This file will process a log file created by the REF_DEBUG
build option in Asterisk.
This file will process a log file created by enabling
the refdebug config option in asterisk.conf.
See http://www.asterisk.org for more information about
the Asterisk project. Please do not directly contact

View File

@ -141,31 +141,11 @@ list. However there is no ordering among elements.
/*
\note DEBUGGING REF COUNTS BIBLE:
An interface to help debug refcounting is provided
in this package. It is dependent on the REF_DEBUG macro being
defined via menuselect and in using variants of the normal ao2_xxxx
function that are named ao2_t_xxxx instead, with an extra argument,
a string that will be printed out into the refs log file when the
refcount for an object is changed.
in this package. It is dependent on the refdebug being enabled in
asterisk.conf.
these ao2_t_xxx variants are provided:
ao2_t_alloc(arg1, arg2, arg3)
ao2_t_ref(arg1,arg2,arg3)
ao2_t_container_alloc(arg1,arg2,arg3,arg4)
ao2_t_link(arg1, arg2, arg3)
ao2_t_unlink(arg1, arg2, arg3)
ao2_t_callback(arg1,arg2,arg3,arg4,arg5)
ao2_t_find(arg1,arg2,arg3,arg4)
ao2_t_iterator_next(arg1, arg2)
If you study each argument list, you will see that these functions all have
one extra argument than their ao2_xxx counterpart. The last argument in
each case is supposed to be a string pointer, a "tag", that should contain
enough of an explanation, that you can pair operations that increment the
ref count, with operations that are meant to decrement the refcount.
Each of these calls will generate at least one line of output in in the refs
log files. These lines look like this:
Each of the reference manipulations will generate one line of output in in the refs
log file. These lines look like this:
...
0x8756f00,+1,1234,chan_sip.c,22240,load_module,**constructor**,allocate users
0x86e3408,+1,1234,chan_sip.c,22241,load_module,**constructor**,allocate peers
@ -210,61 +190,29 @@ follows:
context for the ref change. Note that any subsequent columns are
considered to be part of this tag.
Sometimes you have some helper functions to do object ref/unref
Sometimes you have some helper functions to do object create/ref/unref
operations. Using these normally hides the place where these
functions were called. To get the location where these functions
were called to appear in /refs, you can do this sort of thing:
were called to appear in refs log, you can do this sort of thing:
#ifdef REF_DEBUG
#define dialog_ref(arg1,arg2) dialog_ref_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define dialog_unref(arg1,arg2) dialog_unref_debug((arg1),(arg2), __FILE__, __LINE__, __PRETTY_FUNCTION__)
static struct sip_pvt *dialog_ref_debug(struct sip_pvt *p, const char *tag, const char *file, int line, const char *func)
#define my_t_alloc(data,tag) my_alloc_debug((data), tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define my_alloc(data) my_t_alloc((data), "")
static struct mydata *my_alloc_debug(void *data,
const char *tag, const char *file, int line, const char *func)
{
struct mydata *p;
p = __ao2_alloc(sizeof(*p), NULL, AO2_ALLOC_OPT_LOCK_MUTEX, tag, file, line, func);
if (p) {
ao2_ref_debug(p, 1, tag, file, line, func);
} else {
ast_log(LOG_ERROR, "Attempt to Ref a null pointer\n");
p->data = data;
}
return p;
}
static struct sip_pvt *dialog_unref_debug(struct sip_pvt *p, const char *tag, const char *file, int line, const char *func)
{
if (p) {
ao2_ref_debug(p, -1, tag, file, line, func);
}
return NULL;
}
#else
static struct sip_pvt *dialog_ref(struct sip_pvt *p, const char *tag)
{
if (p) {
ao2_ref(p, 1);
} else {
ast_log(LOG_ERROR, "Attempt to Ref a null pointer\n");
}
return p;
}
static struct sip_pvt *dialog_unref(struct sip_pvt *p, const char *tag)
{
if (p) {
ao2_ref(p, -1);
}
return NULL;
}
#endif
In the above code, note that the "normal" helper funcs call ao2_ref() as
normal, and the "helper" functions call ao2_ref_debug directly with the
file, function, and line number info provided. You might find this
well worth the effort to help track these function calls in the code.
To find out why objects are not destroyed (a common bug), you can
edit the source file to use the ao2_t_* variants, enable REF_DEBUG
in menuselect, and add a descriptive tag to each call. Recompile,
and run Asterisk, exit asterisk with "core stop gracefully", which should
result in every object being destroyed.
enable refdebug in asterisk.conf. Run asterisk, exit with "core stop gracefully".
This should result in every object being destroyed.
Then, you can "sort -k 1 {AST_LOG_DIR}/refs > x1" to get a sorted list of
all the objects, or you can use "contrib/script/refcounter.py" to scan
@ -439,50 +387,23 @@ enum ao2_alloc_opts {
* - the returned pointer cannot be free()'d or realloc()'ed;
* rather, we just call ao2_ref(o, -1);
*
* \note refdebug logging is skipped if debug_msg is NULL
*
* @{
*/
#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)
__ao2_alloc((data_size), (destructor_fn), (options), (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_alloc_options(data_size, destructor_fn, options) \
__ao2_alloc_debug((data_size), (destructor_fn), (options), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_alloc((data_size), (destructor_fn), (options), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_t_alloc(data_size, destructor_fn, debug_msg) \
__ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_alloc(data_size, destructor_fn) \
__ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#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), AO2_ALLOC_OPT_LOCK_MUTEX, (debug_msg), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#define ao2_alloc(data_size, destructor_fn) \
__ao2_alloc_debug((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
#define ao2_t_alloc_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_OPT_LOCK_MUTEX)
#define ao2_alloc(data_size, destructor_fn) \
__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX)
#endif
void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options) attribute_warn_unused_result;
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
/*! @} */
@ -507,20 +428,12 @@ void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned in
* can go away is when we release our reference, and it is
* the last one in existence.
*
* \note refdebug logging is skipped if tag is NULL
* @{
*/
#ifdef REF_DEBUG
#define ao2_t_ref(o,delta,tag) __ao2_ref_debug((o), (delta), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_ref(o,delta) __ao2_ref_debug((o), (delta), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_t_ref(o,delta,tag) __ao2_ref((o), (delta))
#define ao2_ref(o,delta) __ao2_ref((o), (delta))
#endif
#define ao2_t_ref(o,delta,tag) __ao2_ref((o), (delta), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_ref(o,delta) __ao2_ref((o), (delta), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Retrieve the ao2 options used to create the object.
@ -550,8 +463,7 @@ unsigned int ao2_options_get(void *obj);
#define ao2_bump(obj) \
ao2_t_bump((obj), "")
int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *func);
int __ao2_ref(void *o, int delta);
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func);
/*!
* \since 12.4.0
@ -848,20 +760,11 @@ struct ao2_global_obj {
*
* \return Nothing
*/
#ifdef REF_DEBUG
#define ao2_t_global_obj_release(holder, tag) \
__ao2_global_obj_release(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_release(holder) \
__ao2_global_obj_release(&holder, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#else
#define ao2_t_global_obj_release(holder, tag) \
__ao2_global_obj_release(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_release(holder) \
__ao2_global_obj_release(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#endif
void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name);
/*!
@ -879,20 +782,11 @@ void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, co
* \retval Reference to previous global ao2 object stored.
* \retval NULL if no object available.
*/
#ifdef REF_DEBUG
#define ao2_t_global_obj_replace(holder, obj, tag) \
__ao2_global_obj_replace(&holder, (obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_replace(holder, obj) \
__ao2_global_obj_replace(&holder, (obj), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#else
#define ao2_t_global_obj_replace(holder, obj, tag) \
__ao2_global_obj_replace(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_replace(holder, obj) \
__ao2_global_obj_replace(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#endif
void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
/*!
@ -911,20 +805,11 @@ void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const c
* \retval 0 The global object was previously empty
* \retval 1 The global object was not previously empty
*/
#ifdef REF_DEBUG
#define ao2_t_global_obj_replace_unref(holder, obj, tag) \
__ao2_global_obj_replace_unref(&holder, (obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_replace_unref(holder, obj) \
__ao2_global_obj_replace_unref(&holder, (obj), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#else
#define ao2_t_global_obj_replace_unref(holder, obj, tag) \
__ao2_global_obj_replace_unref(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_replace_unref(holder, obj) \
__ao2_global_obj_replace_unref(&holder, (obj), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#endif
int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name);
/*!
@ -937,20 +822,11 @@ int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, con
* \retval Reference to current ao2 object stored in the holder.
* \retval NULL if no object available.
*/
#ifdef REF_DEBUG
#define ao2_t_global_obj_ref(holder, tag) \
__ao2_global_obj_ref(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_ref(holder) \
__ao2_global_obj_ref(&holder, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#else
#define ao2_t_global_obj_ref(holder, tag) \
__ao2_global_obj_ref(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#define ao2_global_obj_ref(holder) \
__ao2_global_obj_ref(&holder, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
#endif
void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
@ -1372,36 +1248,15 @@ struct ao2_container;
* \note Destructor is set implicitly.
*/
#if defined(REF_DEBUG)
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
__ao2_container_alloc_hash_debug((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn) \
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn))
#endif
__ao2_container_alloc_hash((ao2_options), (container_options), (n_buckets), (hash_fn), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
/*!
* \brief Allocate and initialize a list container.
@ -1418,34 +1273,14 @@ struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
* \note Implemented as a degenerate hash table.
*/
#if defined(REF_DEBUG)
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_list_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn))
#endif
__ao2_container_alloc_list((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
/*!
* \brief Allocate and initialize a red-black tree container.
@ -1461,34 +1296,14 @@ struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
* \note Destructor is set implicitly.
*/
#if defined(REF_DEBUG)
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_rbtree_debug((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag) \
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn))
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn) \
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn))
#endif
__ao2_container_alloc_rbtree((ao2_options), (container_options), (sort_fn), (cmp_fn), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
struct ao2_container *__ao2_container_alloc_rbtree(unsigned int ao2_options, unsigned int container_options,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn) attribute_warn_unused_result;
struct ao2_container *__ao2_container_alloc_rbtree_debug(unsigned int ao2_options, unsigned int container_options,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug) attribute_warn_unused_result;
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
/*! \brief
* Returns the number of elements in a container.
@ -1528,24 +1343,13 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
* \retval Clone container on success.
* \retval NULL on error.
*/
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags) attribute_warn_unused_result;
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 *func, int ref_debug) attribute_warn_unused_result;
#if defined(REF_DEBUG)
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags,
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
#define ao2_t_container_clone(orig, flags, tag) __ao2_container_clone_debug(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#define ao2_container_clone(orig, flags) __ao2_container_clone_debug(orig, flags, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 1)
#elif defined(__AST_DEBUG_MALLOC)
#define ao2_t_container_clone(orig, flags, tag) __ao2_container_clone_debug(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#define ao2_container_clone(orig, flags) __ao2_container_clone_debug(orig, flags, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, 0)
#else
#define ao2_t_container_clone(orig, flags, tag) __ao2_container_clone(orig, flags)
#define ao2_container_clone(orig, flags) __ao2_container_clone(orig, flags)
#endif
#define ao2_t_container_clone(orig, flags, tag) \
__ao2_container_clone(orig, flags, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_container_clone(orig, flags) \
__ao2_container_clone(orig, flags, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Print output.
@ -1661,10 +1465,10 @@ void ao2_container_unregister(const char *name);
* \note This function automatically increases the reference count to account
* for the reference that the container now holds to the object.
*/
#ifdef REF_DEBUG
#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(container, obj, tag) \
__ao2_link((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_link(container, obj) \
__ao2_link((container), (obj), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Add an object to a container.
@ -1684,21 +1488,13 @@ void ao2_container_unregister(const char *name);
* \note This function automatically increases the reference count to account
* for the reference that the container now holds to the object.
*/
#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__)
#define ao2_t_link_flags(container, obj, flags, tag) \
__ao2_link((container), (obj), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_link_flags(container, obj, flags) \
__ao2_link((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_flags(container, obj, flags, tag) __ao2_link((container), (obj), (flags))
#define ao2_link_flags(container, obj, flags) __ao2_link((container), (obj), (flags))
#endif
int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func);
int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
int __ao2_link(struct ao2_container *c, void *obj_new, int flags,
const char *tag, const char *file, int line, const char *func);
/*!
* \brief Remove an object from a container
@ -1717,10 +1513,11 @@ int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
* reference to the object will be automatically released. (The
* refcount will be decremented).
*/
#ifdef REF_DEBUG
#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(container, obj, tag) \
__ao2_unlink((container), (obj), 0, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_unlink(container, obj) \
__ao2_unlink((container), (obj), 0, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Remove an object from a container
@ -1741,25 +1538,17 @@ int __ao2_link(struct ao2_container *c, void *obj_new, int flags);
* refcount will be decremented).
*/
#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_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, const char *file, int line, const char *func);
void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
#define ao2_t_unlink_flags(container, obj, flags, tag) \
__ao2_unlink((container), (obj), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_unlink_flags(container, obj, flags) \
__ao2_unlink((container), (obj), (flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
void *__ao2_unlink(struct ao2_container *c, void *obj, int flags,
const char *tag, const char *file, int line, const char *func);
/*@} */
/*! \brief
* ao2_callback() is a generic function that applies cb_fn() to all objects
* in a container, as described below.
@ -1842,26 +1631,15 @@ void *__ao2_unlink(struct ao2_container *c, void *obj, int flags);
*
* @{
*/
#ifdef REF_DEBUG
#define ao2_t_callback(c, flags, cb_fn, arg, tag) \
__ao2_callback_debug((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_callback((c), (flags), (cb_fn), (arg), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_callback(c, flags, cb_fn, arg) \
__ao2_callback_debug((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_callback((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_t_callback(c, flags, cb_fn, arg, tag) \
__ao2_callback((c), (flags), (cb_fn), (arg))
#define ao2_callback(c, flags, cb_fn, arg) \
__ao2_callback((c), (flags), (cb_fn), (arg))
#endif
void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
const char *func);
void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
/*! @} */
@ -1880,50 +1658,27 @@ void *__ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callb
*
* \see ao2_callback()
*/
#ifdef REF_DEBUG
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag) \
__ao2_callback_data_debug((container), (flags), (cb_fn), (arg), (data), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_callback_data(container, flags, cb_fn, arg, data) \
__ao2_callback_data_debug((container), (flags), (cb_fn), (arg), (data), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_t_callback_data(container, flags, cb_fn, arg, data, tag) \
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data))
#define ao2_callback_data(container, flags, cb_fn, arg, data) \
__ao2_callback_data((container), (flags), (cb_fn), (arg), (data))
#endif
void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
int line, const char *func);
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data);
/*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
* XXX possibly change order of arguments ?
*/
#ifdef REF_DEBUG
#define ao2_t_find(container, arg, flags, tag) \
__ao2_find_debug((container), (arg), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_find((container), (arg), (flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_find(container, arg, flags) \
__ao2_find_debug((container), (arg), (flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ao2_find((container), (arg), (flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_t_find(container, arg, flags, tag) \
__ao2_find((container), (arg), (flags))
#define ao2_find(container, arg, flags) \
__ao2_find((container), (arg), (flags))
#endif
void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags,
const char *tag, const char *file, int line, const char *func);
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags);
/*! \brief
*
@ -2083,20 +1838,13 @@ void ao2_iterator_destroy(struct ao2_iterator *iter) __attribute__((noinline));
void ao2_iterator_destroy(struct ao2_iterator *iter);
#endif /* defined(TEST_FRAMEWORK) */
#ifdef REF_DEBUG
#define ao2_t_iterator_next(iter, tag) \
__ao2_iterator_next((iter), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_iterator_next(iter) \
__ao2_iterator_next((iter), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_t_iterator_next(iter, tag) __ao2_iterator_next_debug((iter), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_iterator_next(iter) __ao2_iterator_next_debug((iter), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_t_iterator_next(iter, tag) __ao2_iterator_next((iter))
#define ao2_iterator_next(iter) __ao2_iterator_next((iter))
#endif
void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
void *__ao2_iterator_next(struct ao2_iterator *iter) attribute_warn_unused_result;
void *__ao2_iterator_next(struct ao2_iterator *iter,
const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result;
/*!
* \brief Restart an iteration.
@ -2117,13 +1865,8 @@ void ao2_iterator_restart(struct ao2_iterator *iter);
* down a NULL */
void __ao2_cleanup(void *obj);
void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function);
#ifdef REF_DEBUG
#define ao2_cleanup(obj) __ao2_cleanup_debug((obj), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ao2_t_cleanup(obj, tag) __ao2_cleanup_debug((obj), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ao2_cleanup(obj) __ao2_cleanup(obj)
#define ao2_t_cleanup(obj, tag) __ao2_cleanup((obj))
#endif
void ao2_iterator_cleanup(struct ao2_iterator *iter);
/*!

View File

@ -1186,8 +1186,6 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 16)))
__ast_channel_alloc((needqueue), (state), (cid_num), (cid_name), (acctcode), (exten), (context), (assignedids), (requestor), (amaflag), (endpoint), \
__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
#if defined(REF_DEBUG) || defined(__AST_DEBUG_MALLOC)
/*!
* \brief Create a fake channel structure
*
@ -1206,25 +1204,6 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 15, 16)))
*/
#define ast_dummy_channel_alloc() __ast_dummy_channel_alloc(__FILE__, __LINE__, __PRETTY_FUNCTION__)
struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const char *function);
#else
/*!
* \brief Create a fake channel structure
*
* \retval NULL failure
* \retval non-NULL successfully allocated channel
*
* \note This function should ONLY be used to create a fake channel
* that can then be populated with data for use in variable
* substitution when a real channel does not exist.
*
* \note The created dummy channel should be destroyed by
* ast_channel_unref(). Using ast_channel_release() needlessly
* grabs the channel container lock and can cause a deadlock as
* a result. Also grabbing the channel container lock reduces
* system performance.
*/
struct ast_channel *ast_dummy_channel_alloc(void);
#endif
/*!
* \brief Queue one or more frames to a channel's frame queue

View File

@ -252,20 +252,13 @@ int ast_format_cache_set(struct ast_format *format);
* \note The returned format has its reference count incremented. It must be
* dropped using ao2_ref or ao2_cleanup.
*/
struct ast_format *__ast_format_cache_get(const char *name);
struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func);
struct ast_format *__ast_format_cache_get(const char *name,
const char *tag, const char *file, int line, const char *func);
#ifdef REF_DEBUG
#define ast_format_cache_get(name) \
__ast_format_cache_get_debug((name), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ast_format_cache_get((name), "ast_format_cache_get", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_t_format_cache_get(name, tag) \
__ast_format_cache_get_debug((name), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ast_format_cache_get(name) \
__ast_format_cache_get((name))
#define ast_t_format_cache_get(name, tag) \
__ast_format_cache_get((name))
#endif
__ast_format_cache_get((name), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!

View File

@ -46,20 +46,14 @@ enum ast_format_cap_flags {
* \retval ast_format_cap object on success.
* \retval NULL on failure.
*/
struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags);
struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func);
struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags,
const char *tag, const char *file, int line, const char *func);
#ifdef REF_DEBUG
#define ast_format_cap_alloc(flags) \
__ast_format_cap_alloc_debug((flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ast_format_cap_alloc((flags), "ast_format_cap_alloc", \
__FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_t_format_cap_alloc(flags, tag) \
__ast_format_cap_alloc_debug((flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ast_format_cap_alloc(flags) \
__ast_format_cap_alloc((flags))
#define ast_t_format_cap_alloc(flags, tag) \
__ast_format_cap_alloc((flags))
#endif
__ast_format_cap_alloc((flags), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Set the global framing.
@ -103,20 +97,15 @@ unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap);
*
* \note If framing is specified here it overrides any global framing that has been set.
*/
int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing);
int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func);
int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing,
const char *tag, const char *file, int line, const char *func);
#ifdef REF_DEBUG
#define ast_format_cap_append(cap, format, framing) \
__ast_format_cap_append_debug((cap), (format), (framing), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
__ast_format_cap_append((cap), (format), (framing), "ast_format_cap_append", \
__FILE__, __LINE__, __PRETTY_FUNCTION__)
#define ast_t_format_cap_append(cap, format, framing, tag) \
__ast_format_cap_append_debug((cap), (format), (framing), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
#else
#define ast_format_cap_append(cap, format, framing) \
__ast_format_cap_append((cap), (format), (framing))
#define ast_t_format_cap_append(cap, format, framing, tag) \
__ast_format_cap_append((cap), (format), (framing))
#endif
__ast_format_cap_append((cap), (format), (framing), (tag), \
__FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Add all codecs Asterisk knows about for a specific type to

View File

@ -76,6 +76,8 @@ enum ast_option_flags {
AST_OPT_FLAG_DONT_WARN = (1 << 18),
/*! End CDRs before the 'h' extension */
AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
/*! Reference Debugging */
AST_OPT_FLAG_REF_DEBUG = (1 << 20),
/*! Always fork, even if verbose or debug settings are non-zero */
AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
/*! Disable log/verbose output to remote consoles */
@ -131,6 +133,7 @@ enum ast_option_flags {
#define ast_opt_hide_connect ast_test_flag(&ast_options, AST_OPT_FLAG_HIDE_CONSOLE_CONNECT)
#define ast_opt_lock_confdir ast_test_flag(&ast_options, AST_OPT_FLAG_LOCK_CONFIG_DIR)
#define ast_opt_generic_plc ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC)
#define ast_opt_ref_debug ast_test_flag(&ast_options, AST_OPT_FLAG_REF_DEBUG)
extern struct ast_flags ast_options;

View File

@ -3424,6 +3424,12 @@ static void ast_readconfig(void)
ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
#ifdef REF_DEBUG
/* The REF_DEBUG compiler flag is now only used to enable refdebug by default.
* Support for debugging reference counts is always compiled in. */
ast_set2_flag(&ast_options, 1, AST_OPT_FLAG_REF_DEBUG);
#endif
ast_set_default_eid(&ast_eid_default);
/* no asterisk.conf? no problem, use buildtime config! */
@ -3494,6 +3500,8 @@ static void ast_readconfig(void)
if (sscanf(v->value, "%30d", &option_debug) != 1) {
option_debug = ast_true(v->value);
}
} else if (!strcasecmp(v->name, "refdebug")) {
ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_REF_DEBUG);
#if HAVE_WORKING_FORK
/* Disable forking (-f at startup) */
} else if (!strcasecmp(v->name, "nofork")) {

View File

@ -118,36 +118,28 @@ struct ao2_stats ao2;
#define INTERNAL_OBJ_RWLOCK(user_data) \
((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
#define INTERNAL_OBJ(user_data) \
(struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))
/*!
* \brief convert from a pointer _p to a user-defined object
*
* \return the pointer to the astobj2 structure
*/
static struct astobj2 *INTERNAL_OBJ(void *user_data)
{
struct astobj2 *p;
#define __INTERNAL_OBJ_CHECK(user_data, file, line, func) \
({ \
struct astobj2 *p ## __LINE__; \
if (!user_data \
|| !(p ## __LINE__ = INTERNAL_OBJ(user_data)) \
|| IS_AO2_MAGIC_BAD(p ## __LINE__)) { \
log_bad_ao2(user_data, file, line, func); \
p ## __LINE__ = NULL; \
} \
(p ## __LINE__); \
})
if (!user_data) {
ast_log(LOG_ERROR, "user_data is NULL\n");
return NULL;
}
p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
if (IS_AO2_MAGIC_BAD(p)) {
if (p->priv_data.magic) {
ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
p->priv_data.magic, user_data);
} else {
ast_log(LOG_ERROR,
"bad magic number for object %p. Object is likely destroyed.\n",
user_data);
}
ast_assert(0);
return NULL;
}
return p;
}
#define INTERNAL_OBJ_CHECK(user_data) \
__INTERNAL_OBJ_CHECK(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief convert from a pointer _p to an astobj2 object
@ -156,14 +148,43 @@ static struct astobj2 *INTERNAL_OBJ(void *user_data)
*/
#define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
int is_ao2_object(void *user_data)
int internal_is_ao2_object(void *user_data)
{
return (INTERNAL_OBJ(user_data) != NULL);
struct astobj2 *p;
if (!user_data) {
return 0;
}
p = INTERNAL_OBJ(user_data);
return !p || IS_AO2_MAGIC_BAD(p) ? 0 : 1;
}
void log_bad_ao2(void *user_data, const char *file, int line, const char *func)
{
struct astobj2 *p;
if (!user_data) {
ast_log(__LOG_ERROR, file, line, func, "user_data is NULL\n");
return;
}
p = INTERNAL_OBJ(user_data);
if (p->priv_data.magic) {
ast_log(__LOG_ERROR, file, line, func,
"bad magic number 0x%x for object %p\n",
p->priv_data.magic, user_data);
} else {
ast_log(__LOG_ERROR, file, line, func,
"bad magic number for object %p. Object is likely destroyed.\n",
user_data);
}
}
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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
struct astobj2_lock *obj_mutex;
struct astobj2_rwlock *obj_rwlock;
int res = 0;
@ -221,7 +242,7 @@ int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, co
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
struct astobj2_lock *obj_mutex;
struct astobj2_rwlock *obj_rwlock;
int res = 0;
@ -271,7 +292,7 @@ int __ao2_unlock(void *user_data, const char *file, const char *func, int line,
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 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
struct astobj2_lock *obj_mutex;
struct astobj2_rwlock *obj_rwlock;
int res = 0;
@ -393,9 +414,11 @@ enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int
void *ao2_object_get_lockaddr(void *user_data)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
struct astobj2 *obj;
struct astobj2_lock *obj_mutex;
obj = INTERNAL_OBJ_CHECK(user_data);
if (obj == NULL) {
ast_assert(0);
return NULL;
@ -412,9 +435,10 @@ void *ao2_object_get_lockaddr(void *user_data)
return NULL;
}
static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func)
int __ao2_ref(void *user_data, int delta,
const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
struct astobj2_lock *obj_mutex;
struct astobj2_rwlock *obj_rwlock;
int current_value;
@ -422,6 +446,11 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
void *weakproxy = NULL;
if (obj == NULL) {
if (ref_log && user_data) {
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
fflush(ref_log);
}
ast_assert(0);
return -1;
}
@ -446,7 +475,9 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
if (weakproxy) {
if (current_value == 1) {
/* The only remaining reference is the one owned by the weak object */
struct astobj2 *internal_weakproxy = INTERNAL_OBJ(weakproxy);
struct astobj2 *internal_weakproxy;
internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
/* Unlink the obj from the weak proxy */
internal_weakproxy->priv_data.weakptr = NULL;
@ -468,6 +499,12 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
if (0 < current_value) {
/* The object still lives. */
if (ref_log && tag) {
fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data,
(delta < 0 ? "" : "+"), delta, ast_get_tid(),
file, line, func, ret, tag);
fflush(ref_log);
}
return ret;
}
@ -475,6 +512,12 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
if (current_value < 0) {
ast_log(__LOG_ERROR, file, line, func,
"Invalid refcount %d on ao2 object %p\n", current_value, user_data);
if (ref_log) {
/* Log to ref_log invalid even if (tag == NULL) */
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
fflush(ref_log);
}
ast_assert(0);
/* stop here even if assert doesn't DO_CRASH */
return -1;
@ -515,51 +558,19 @@ static int internal_ao2_ref(void *user_data, int delta, const char *file, int li
break;
}
if (ref_log && tag) {
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
user_data, delta, ast_get_tid(), file, line, func, tag);
fflush(ref_log);
}
return ret;
}
int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
int old_refcount = -1;
if (obj) {
old_refcount = internal_ao2_ref(user_data, delta, file, line, func);
}
if (ref_log && user_data) {
if (!obj) {
/* Invalid object: Bad magic number. */
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
user_data, delta, ast_get_tid(), file, line, func, tag);
fflush(ref_log);
} else if (old_refcount + delta == 0) {
fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
user_data, delta, ast_get_tid(), file, line, func, tag);
fflush(ref_log);
} else if (delta != 0) {
fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"),
delta, ast_get_tid(), file, line, func, old_refcount, tag);
fflush(ref_log);
}
}
if (obj == NULL) {
ast_assert(0);
}
return old_refcount;
}
int __ao2_ref(void *user_data, int delta)
{
return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
}
void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
{
if (obj) {
__ao2_ref_debug(obj, -1, tag, file, line, function);
__ao2_ref(obj, -1, tag, file, line, function);
}
}
@ -570,7 +581,8 @@ void __ao2_cleanup(void *obj)
}
}
static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func)
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
const char *tag, const char *file, int line, const char *func)
{
/* allocation */
struct astobj2 *obj;
@ -633,43 +645,27 @@ static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_f
ast_atomic_fetchadd_int(&ao2.total_refs, 1);
#endif
if (ref_log && tag) {
fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n",
EXTERNAL_OBJ(obj), ast_get_tid(), file, line, func, tag);
fflush(ref_log);
}
/* return a pointer to the user data */
return EXTERNAL_OBJ(obj);
}
unsigned int ao2_options_get(void *obj)
{
struct astobj2 *orig_obj = INTERNAL_OBJ(obj);
struct astobj2 *orig_obj;
orig_obj = INTERNAL_OBJ_CHECK(obj);
if (!orig_obj) {
return 0;
}
return orig_obj->priv_data.options;
}
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 *func, int ref_debug)
{
/* allocation */
void *obj;
if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, func)) == NULL) {
return NULL;
}
if (ref_log) {
fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj, ast_get_tid(), file, line, func, tag);
fflush(ref_log);
}
/* return a pointer to the user data */
return obj;
}
void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options)
{
return internal_ao2_alloc(data_size, destructor_fn, options, __FILE__, __LINE__, __FUNCTION__);
}
void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
{
@ -687,11 +683,7 @@ void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, co
/* Release the held ao2 object. */
if (holder->obj) {
if (tag) {
__ao2_ref_debug(holder->obj, -1, tag, file, line, func);
} else {
__ao2_ref(holder->obj, -1);
}
__ao2_ref(holder->obj, -1, tag, file, line, func);
holder->obj = NULL;
}
@ -715,11 +707,7 @@ void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const c
}
if (obj) {
if (tag) {
__ao2_ref_debug(obj, +1, tag, file, line, func);
} else {
__ao2_ref(obj, +1);
}
__ao2_ref(obj, +1, tag, file, line, func);
}
obj_old = holder->obj;
holder->obj = obj;
@ -735,11 +723,7 @@ int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, con
obj_old = __ao2_global_obj_replace(holder, obj, tag, file, line, func, name);
if (obj_old) {
if (tag) {
__ao2_ref_debug(obj_old, -1, tag, file, line, func);
} else {
__ao2_ref(obj_old, -1);
}
__ao2_ref(obj_old, -1, tag, file, line, func);
return 1;
}
return 0;
@ -764,11 +748,7 @@ void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const
obj = holder->obj;
if (obj) {
if (tag) {
__ao2_ref_debug(obj, +1, tag, file, line, func);
} else {
__ao2_ref(obj, +1);
}
__ao2_ref(obj, +1, tag, file, line, func);
}
__ast_rwlock_unlock(file, line, func, &holder->lock, name);
@ -798,12 +778,14 @@ void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn,
return NULL;
}
weakproxy = __ao2_alloc_debug(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_MUTEX,
tag, file, line, func, 1);
weakproxy = __ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_MUTEX,
tag, file, line, func);
if (weakproxy) {
struct astobj2 *weakproxy_internal = INTERNAL_OBJ(weakproxy);
struct astobj2 *weakproxy_internal;
/* Just created weakproxy, no need to check if it's valid. */
weakproxy_internal = INTERNAL_OBJ(weakproxy);
weakproxy_internal->priv_data.magic = AO2_WEAK;
}
@ -813,8 +795,8 @@ void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn,
int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *weakproxy_internal = INTERNAL_OBJ(weakproxy);
struct astobj2 *obj_internal = INTERNAL_OBJ(obj);
struct astobj2 *weakproxy_internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
int ret = -1;
if (!weakproxy_internal
@ -833,8 +815,8 @@ int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
}
if (!weakproxy_internal->priv_data.weakptr) {
__ao2_ref_debug(obj, +1, tag, file, line, func);
__ao2_ref_debug(weakproxy, +1, tag, file, line, func);
__ao2_ref(obj, +1, tag, file, line, func);
__ao2_ref(weakproxy, +1, tag, file, line, func);
weakproxy_internal->priv_data.weakptr = obj;
obj_internal->priv_data.weakptr = weakproxy;
@ -857,7 +839,7 @@ int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *internal = INTERNAL_OBJ(weakproxy);
struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
void *obj;
if (!internal || internal->priv_data.magic != AO2_WEAK) {
@ -872,7 +854,7 @@ void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
obj = internal->priv_data.weakptr;
if (obj) {
__ao2_ref_debug(obj, +1, tag, file, line, func);
__ao2_ref(obj, +1, tag, file, line, func);
}
if (!(flags & OBJ_NOLOCK)) {
@ -884,7 +866,7 @@ void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
void *__ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
{
struct astobj2 *obj_internal = INTERNAL_OBJ(obj);
struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
if (!obj_internal || obj_internal->priv_data.magic != AO2_MAGIC) {
/* This method is meant to be run on normal ao2 objects! */
@ -895,13 +877,13 @@ void *__ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line
return NULL;
}
__ao2_ref_debug(obj_internal->priv_data.weakptr, +1, tag, file, line, func);
__ao2_ref(obj_internal->priv_data.weakptr, +1, tag, file, line, func);
return obj_internal->priv_data.weakptr;
}
int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
{
struct astobj2 *weakproxy_internal = INTERNAL_OBJ(weakproxy);
struct astobj2 *weakproxy_internal = INTERNAL_OBJ_CHECK(weakproxy);
int ret = -1;
if (!weakproxy_internal || weakproxy_internal->priv_data.magic != AO2_WEAK) {
@ -936,7 +918,7 @@ int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, v
int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
{
struct astobj2 *internal_weakproxy = INTERNAL_OBJ(weakproxy);
struct astobj2 *internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
struct ao2_weakproxy *weak;
struct ao2_weakproxy_notification *sub;
int ret = 0;
@ -1123,29 +1105,28 @@ static void astobj2_cleanup(void)
#if defined(AO2_DEBUG)
ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
#endif
#ifdef REF_DEBUG
fclose(ref_log);
ref_log = NULL;
#endif
if (ast_opt_ref_debug) {
fclose(ref_log);
ref_log = NULL;
}
}
int astobj2_init(void)
{
#ifdef REF_DEBUG
char ref_filename[1024];
#endif
if (container_init() != 0) {
return -1;
}
#ifdef REF_DEBUG
snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
ref_log = fopen(ref_filename, "w");
if (!ref_log) {
ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
if (ast_opt_ref_debug) {
snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
ref_log = fopen(ref_filename, "w");
if (!ref_log) {
ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
}
}
#endif
#if defined(AO2_DEBUG)
ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));

View File

@ -49,11 +49,7 @@ int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flag
if ((flags & AO2_UNLINK_NODE_UNLINK_OBJECT)
&& !(flags & AO2_UNLINK_NODE_NOUNREF_OBJECT)) {
if (tag) {
__ao2_ref_debug(node->obj, -1, tag, file, line, func);
} else {
ao2_t_ref(node->obj, -1, "Remove obj from container");
}
__ao2_ref(node->obj, -1, tag ?: "Remove obj from container", file, line, func);
}
node->obj = NULL;
@ -76,7 +72,7 @@ int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flag
if (flags & AO2_UNLINK_NODE_UNREF_NODE) {
/* Remove node from container */
__ao2_ref(node, -1);
ao2_t_ref(node, -1, NULL);
}
return 1;
@ -97,13 +93,15 @@ int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flag
* \retval 0 on errors.
* \retval 1 on success.
*/
static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
int __ao2_link(struct ao2_container *self, void *obj_new, int flags,
const char *tag, const char *file, int line, const char *func)
{
int res;
enum ao2_lock_req orig_lock;
struct ao2_container_node *node;
if (!is_ao2_object(obj_new) || !is_ao2_object(self)
if (!__is_ao2_object(obj_new, file, line, func)
|| !__is_ao2_object(self, file, line, func)
|| !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
/* Sanity checks. */
ast_assert(0);
@ -147,7 +145,7 @@ static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flag
res = 1;
break;
case AO2_CONTAINER_INSERT_NODE_REJECTED:
__ao2_ref(node, -1);
ao2_t_ref(node, -1, NULL);
break;
}
}
@ -161,16 +159,6 @@ static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flag
return res;
}
int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
{
return internal_ao2_link(c, obj_new, flags, tag, file, line, func);
}
int __ao2_link(struct ao2_container *c, void *obj_new, int flags)
{
return internal_ao2_link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
}
/*!
* \brief another convenience function is a callback that matches on address
*/
@ -183,10 +171,10 @@ int ao2_match_by_addr(void *user_data, void *arg, int flags)
* Unlink an object from the container
* and destroy the associated * bucket_entry structure.
*/
void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags,
const char *tag, const char *file, int line, const char *func)
{
if (!is_ao2_object(user_data)) {
if (!__is_ao2_object(user_data, file, line, func)) {
/* Sanity checks. */
ast_assert(0);
return NULL;
@ -194,22 +182,7 @@ void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
flags &= ~OBJ_SEARCH_MASK;
flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
__ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
return NULL;
}
void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
{
if (!is_ao2_object(user_data)) {
/* Sanity checks. */
ast_assert(0);
return NULL;
}
flags &= ~OBJ_SEARCH_MASK;
flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
__ao2_callback(c, flags, ao2_match_by_addr, user_data);
__ao2_callback(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
return NULL;
}
@ -268,8 +241,8 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
struct ao2_container *multi_container = NULL;
struct ao2_iterator *multi_iterator = NULL;
if (!is_ao2_object(self) || !self->v_table || !self->v_table->traverse_first
|| !self->v_table->traverse_next) {
if (!__is_ao2_object(self, file, line, func) || !self->v_table
|| !self->v_table->traverse_first || !self->v_table->traverse_next) {
/* Sanity checks. */
ast_assert(0);
return NULL;
@ -376,12 +349,7 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
* Link the object into the container that will hold the
* results.
*/
if (tag) {
__ao2_link_debug(multi_container, node->obj, flags,
tag, file, line, func);
} else {
__ao2_link(multi_container, node->obj, flags);
}
__ao2_link(multi_container, node->obj, flags, tag, file, line, func);
} else {
ret = node->obj;
/* Returning a single object. */
@ -390,11 +358,7 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
* Bump the ref count since we are not going to unlink and
* transfer the container's object ref to the returned object.
*/
if (tag) {
__ao2_ref_debug(ret, 1, tag, file, line, func);
} else {
ao2_t_ref(ret, 1, "Traversal found object");
}
__ao2_ref(ret, 1, tag ?: "Traversal found object", file, line, func);
}
}
}
@ -418,7 +382,7 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
}
if (node) {
/* Unref the node from self->v_table->traverse_first/traverse_next() */
__ao2_ref(node, -1);
ao2_t_ref(node, -1, NULL);
}
if (flags & OBJ_NOLOCK) {
@ -439,36 +403,24 @@ static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags
}
}
void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
const char *func)
{
return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, file, line, func);
}
void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
ao2_callback_fn *cb_fn, void *arg)
{
return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, NULL, NULL, 0, NULL);
}
void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
int line, const char *func)
{
return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, file, line, func);
}
void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
ao2_callback_data_fn *cb_fn, void *arg, void *data)
{
return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, NULL, NULL, 0, NULL);
}
/*!
* the find function just invokes the default callback with some reasonable flags.
*/
void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags,
const char *tag, const char *file, int line, const char *func)
{
void *arged = (void *) arg;/* Done to avoid compiler const warning */
@ -478,19 +430,7 @@ void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_fla
ast_assert(0);
return NULL;
}
return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, func);
}
void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags)
{
void *arged = (void *) arg;/* Done to avoid compiler const warning */
if (!c) {
/* Sanity checks. */
ast_assert(0);
return NULL;
}
return __ao2_callback(c, flags, c->cmp_fn, arged);
return __ao2_callback(c, flags, c->cmp_fn, arged, tag, file, line, func);
}
/*!
@ -520,6 +460,12 @@ void ao2_iterator_restart(struct ao2_iterator *iter)
if (iter->last_node) {
enum ao2_lock_req orig_lock;
if (!is_ao2_object(iter->c)) {
/* Sanity check. */
ast_assert(0);
return;
}
/*
* Do a read lock in case the container node unref does not
* destroy the node. If the container node is destroyed then
@ -532,7 +478,7 @@ void ao2_iterator_restart(struct ao2_iterator *iter)
ao2_rdlock(iter->c);
}
__ao2_ref(iter->last_node, -1);
ao2_t_ref(iter->last_node, -1, NULL);
iter->last_node = NULL;
if (iter->flags & AO2_ITERATOR_DONTLOCK) {
@ -568,16 +514,15 @@ void ao2_iterator_cleanup(struct ao2_iterator *iter)
}
}
/*
* move to the next element in the container.
*/
static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
void *__ao2_iterator_next(struct ao2_iterator *iter,
const char *tag, const char *file, int line, const char *func)
{
enum ao2_lock_req orig_lock;
struct ao2_container_node *node;
void *ret;
if (!is_ao2_object(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
if (!__is_ao2_object(iter->c, file, line, func)
|| !iter->c->v_table || !iter->c->v_table->iterator_next) {
/* Sanity checks. */
ast_assert(0);
return NULL;
@ -614,14 +559,10 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *t
/* Transfer the container's node ref to the iterator. */
} else {
/* Bump ref of returned object */
if (tag) {
__ao2_ref_debug(ret, +1, tag, file, line, func);
} else {
ao2_t_ref(ret, +1, "Next iterator object.");
}
__ao2_ref(ret, +1, tag ?: "Next iterator object.", file, line, func);
/* Bump the container's node ref for the iterator. */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
}
} else {
/* The iteration has completed. */
@ -631,7 +572,7 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *t
/* Replace the iterator's node */
if (iter->last_node) {
__ao2_ref(iter->last_node, -1);
ao2_t_ref(iter->last_node, -1, NULL);
}
iter->last_node = node;
@ -644,16 +585,6 @@ static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *t
return ret;
}
void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
{
return internal_ao2_iterator_next(iter, tag, file, line, func);
}
void *__ao2_iterator_next(struct ao2_iterator *iter)
{
return internal_ao2_iterator_next(iter, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
}
int ao2_iterator_count(struct ao2_iterator *iter)
{
return ao2_container_count(iter->c);
@ -665,26 +596,8 @@ void container_destruct(void *_c)
/* Unlink any stored objects in the container. */
c->destroying = 1;
__ao2_callback(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
/* Perform any extra container cleanup. */
if (c->v_table && c->v_table->destroy) {
c->v_table->destroy(c);
}
#if defined(AO2_DEBUG)
ast_atomic_fetchadd_int(&ao2.total_containers, -1);
#endif
}
void container_destruct_debug(void *_c)
{
struct ao2_container *c = _c;
/* Unlink any stored objects in the container. */
c->destroying = 1;
__ao2_callback_debug(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL,
"container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
ao2_t_callback(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL,
"container_destruct called");
/* Perform any extra container cleanup. */
if (c->v_table && c->v_table->destroy) {
@ -712,7 +625,7 @@ static int dup_obj_cb(void *obj, void *arg, int flags)
{
struct ao2_container *dest = arg;
return __ao2_link(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
return ao2_t_link_flags(dest, obj, OBJ_NOLOCK, NULL) ? 0 : (CMP_MATCH | CMP_STOP);
}
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
@ -724,14 +637,14 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
ao2_rdlock(src);
ao2_wrlock(dest);
}
obj = __ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
obj = ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
if (obj) {
/* Failed to put this obj into the dest container. */
ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
/* Remove all items from the dest container. */
__ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
NULL);
ao2_t_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
NULL, NULL);
res = -1;
}
if (!(flags & OBJ_NOLOCK)) {
@ -742,18 +655,19 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
return res;
}
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags)
struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
{
struct ao2_container *clone;
int failed;
/* Create the clone container with the same properties as the original. */
if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone) {
if (!__is_ao2_object(orig, file, line, func)
|| !orig->v_table || !orig->v_table->alloc_empty_clone) {
/* Sanity checks. */
ast_assert(0);
return NULL;
}
clone = orig->v_table->alloc_empty_clone(orig);
clone = orig->v_table->alloc_empty_clone(orig, tag, file, line, func);
if (!clone) {
return NULL;
}
@ -767,42 +681,7 @@ struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum sea
}
if (failed) {
/* Object copy into the clone container failed. */
ao2_t_ref(clone, -1, "Clone creation failed.");
clone = NULL;
}
return clone;
}
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 *func, int ref_debug)
{
struct ao2_container *clone;
int failed;
/* Create the clone container with the same properties as the original. */
if (!is_ao2_object(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone_debug) {
/* Sanity checks. */
ast_assert(0);
return NULL;
}
clone = orig->v_table->alloc_empty_clone_debug(orig, tag, file, line, func, ref_debug);
if (!clone) {
return NULL;
}
if (flags & OBJ_NOLOCK) {
ao2_wrlock(clone);
}
failed = ao2_container_dup(clone, orig, flags);
if (flags & OBJ_NOLOCK) {
ao2_unlock(clone);
}
if (failed) {
/* Object copy into the clone container failed. */
if (ref_debug) {
__ao2_ref_debug(clone, -1, tag, file, line, func);
} else {
ao2_t_ref(clone, -1, "Clone creation failed.");
}
__ao2_ref(clone, -1, tag ?: "Clone creation failed", file, line, func);
clone = NULL;
}
return clone;

View File

@ -87,26 +87,15 @@ typedef void (*ao2_container_destroy_fn)(struct ao2_container *self);
* \brief Create an empty copy of this container.
*
* \param self Container to operate upon.
*
* \retval empty-container on success.
* \retval NULL on error.
*/
typedef struct ao2_container *(*ao2_container_alloc_empty_clone_fn)(struct ao2_container *self);
/*!
* \brief Create an empty copy of this container. (Debug version)
*
* \param self Container to operate upon.
* \param tag used for debugging.
* \param file Debug file name invoked from
* \param line Debug line invoked from
* \param func Debug function name invoked from
* \param ref_debug TRUE if to output a debug reference message.
*
* \retval empty-container on success.
* \retval NULL on error.
*/
typedef struct ao2_container *(*ao2_container_alloc_empty_clone_debug_fn)(struct ao2_container *self, const char *tag, const char *file, int line, const char *func, int ref_debug);
typedef struct ao2_container *(*ao2_container_alloc_empty_clone_fn)(struct ao2_container *self, const char *tag, const char *file, int line, const char *func);
/*!
* \brief Create a new container node.
@ -250,8 +239,6 @@ struct ao2_container_methods {
ao2_container_destroy_fn destroy;
/*! \brief Create an empty copy of this container. */
ao2_container_alloc_empty_clone_fn alloc_empty_clone;
/*! \brief Create an empty copy of this container. (Debug version) */
ao2_container_alloc_empty_clone_debug_fn alloc_empty_clone_debug;
/*! Create a new container node. */
ao2_container_new_node_fn new_node;
/*! Insert a node into this container. */
@ -336,10 +323,9 @@ int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flag
const char *tag, const char *file, int line, const char *func);
#define __container_unlink_node(node, flags) \
__container_unlink_node_debug(node, flags, NULL, NULL, 0, NULL)
__container_unlink_node_debug(node, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__)
void container_destruct(void *_c);
void container_destruct_debug(void *_c);
int container_init(void);
#endif /* ASTOBJ2_CONTAINER_PRIVATE_H_ */

View File

@ -104,47 +104,27 @@ struct hash_traversal_state_check {
/*!
* \internal
* \brief Create an empty copy of this container.
* \since 12.0.0
*
* \param self Container to operate upon.
*
* \retval empty-clone-container on success.
* \retval NULL on error.
*/
static struct ao2_container *hash_ao2_alloc_empty_clone(struct ao2_container_hash *self)
{
if (!is_ao2_object(self)) {
return NULL;
}
return ao2_t_container_alloc_hash(ao2_options_get(self), self->common.options, self->n_buckets,
self->hash_fn, self->common.sort_fn, self->common.cmp_fn, "Clone hash container");
}
/*!
* \internal
* \brief Create an empty copy of this container. (Debug version)
* \since 12.0.0
* \since 14.0.0
*
* \param self Container to operate upon.
* \param tag used for debugging.
* \param file Debug file name invoked from
* \param line Debug line invoked from
* \param func Debug function name invoked from
* \param ref_debug TRUE if to output a debug reference message.
*
* \retval empty-clone-container on success.
* \retval NULL on error.
*/
static struct ao2_container *hash_ao2_alloc_empty_clone_debug(struct ao2_container_hash *self, const char *tag, const char *file, int line, const char *func, int ref_debug)
static struct ao2_container *hash_ao2_alloc_empty_clone(struct ao2_container_hash *self,
const char *tag, const char *file, int line, const char *func)
{
if (!is_ao2_object(self)) {
if (!__is_ao2_object(self, file, line, func)) {
return NULL;
}
return __ao2_container_alloc_hash_debug(ao2_options_get(self), self->common.options,
return __ao2_container_alloc_hash(ao2_options_get(self), self->common.options,
self->n_buckets, self->hash_fn, self->common.sort_fn, self->common.cmp_fn,
tag, file, line, func, ref_debug);
tag, file, line, func);
}
/*!
@ -230,7 +210,7 @@ static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *sel
struct hash_bucket_node *node;
int i;
node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
node = ao2_t_alloc_options(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK, NULL);
if (!node) {
return NULL;
}
@ -238,11 +218,7 @@ static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *sel
i = abs(self->hash_fn(obj_new, OBJ_SEARCH_OBJECT));
i %= self->n_buckets;
if (tag) {
__ao2_ref_debug(obj_new, +1, tag, file, line, func);
} else {
ao2_t_ref(obj_new, +1, "Container node creation");
}
__ao2_ref(obj_new, +1, tag ?: "Container node creation", file, line, func);
node->common.obj = obj_new;
node->common.my_container = (struct ao2_container *) self;
node->my_bucket = i;
@ -440,7 +416,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
}
/* We have the first traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
return node;
}
}
@ -482,7 +458,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
}
/* We have the first traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
return node;
}
}
@ -551,7 +527,7 @@ static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *se
}
/* We have the next traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
/*
* Dereferencing the prev node may result in our next node
@ -559,7 +535,7 @@ static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *se
* the container uses RW locks and the container was read
* locked.
*/
__ao2_ref(prev, -1);
ao2_t_ref(prev, -1, NULL);
if (node->common.obj) {
return node;
}
@ -595,7 +571,7 @@ hash_descending_resume:;
}
/* We have the next traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
/*
* Dereferencing the prev node may result in our next node
@ -603,7 +579,7 @@ hash_descending_resume:;
* the container uses RW locks and the container was read
* locked.
*/
__ao2_ref(prev, -1);
ao2_t_ref(prev, -1, NULL);
if (node->common.obj) {
return node;
}
@ -615,7 +591,7 @@ hash_ascending_resume:;
}
/* No more nodes in the container left to traverse. */
__ao2_ref(prev, -1);
ao2_t_ref(prev, -1, NULL);
return NULL;
}
@ -1037,8 +1013,6 @@ static int hash_ao2_integrity(struct ao2_container_hash *self)
/*! Hash container virtual method table. */
static const struct ao2_container_methods v_table_hash = {
.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) hash_ao2_alloc_empty_clone,
.alloc_empty_clone_debug =
(ao2_container_alloc_empty_clone_debug_fn) hash_ao2_alloc_empty_clone_debug,
.new_node = (ao2_container_new_node_fn) hash_ao2_new_node,
.insert = (ao2_container_insert_fn) hash_ao2_insert_node,
.traverse_first = (ao2_container_find_first_fn) hash_ao2_find_first,
@ -1103,26 +1077,9 @@ static struct ao2_container *hash_ao2_container_init(
}
struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
{
unsigned int num_buckets;
size_t container_size;
struct ao2_container_hash *self;
num_buckets = hash_fn ? n_buckets : 1;
container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
self = ao2_t_alloc_options(container_size, container_destruct, ao2_options,
"New hash container");
return hash_ao2_container_init(self, container_options, num_buckets,
hash_fn, sort_fn, cmp_fn);
}
struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug)
const char *tag, const char *file, int line, const char *func)
{
unsigned int num_buckets;
size_t container_size;
@ -1131,25 +1088,17 @@ struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
num_buckets = hash_fn ? n_buckets : 1;
container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
self = __ao2_alloc_debug(container_size,
ref_debug ? container_destruct_debug : container_destruct, ao2_options,
tag, file, line, func, ref_debug);
self = __ao2_alloc(container_size, container_destruct, ao2_options,
tag ?: __PRETTY_FUNCTION__, file, line, func);
return hash_ao2_container_init(self, container_options, num_buckets, hash_fn,
sort_fn, cmp_fn);
}
struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
{
return __ao2_container_alloc_hash(ao2_options, container_options, 1, NULL, sort_fn,
cmp_fn);
}
struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug)
const char *tag, const char *file, int line, const char *func)
{
return __ao2_container_alloc_hash_debug(ao2_options, container_options, 1, NULL,
sort_fn, cmp_fn, tag, file, line, func, ref_debug);
return __ao2_container_alloc_hash(ao2_options, container_options, 1, NULL,
sort_fn, cmp_fn, tag, file, line, func);
}

View File

@ -43,7 +43,24 @@ struct ao2_stats {
extern struct ao2_stats ao2;
#endif /* defined(AO2_DEBUG) */
int is_ao2_object(void *user_data);
void log_bad_ao2(void *user_data, const char *file, int line, const char *func);
int internal_is_ao2_object(void *user_data);
#define __is_ao2_object(user_data, file, line, func) \
({ \
int ret ## __LINE__ = 0; \
if (user_data) { \
ret ## __LINE__ = internal_is_ao2_object(user_data); \
} \
if (!ret ## __LINE__) { \
log_bad_ao2(user_data, file, line, func); \
} \
(ret ## __LINE__); \
})
#define is_ao2_object(user_data) \
__is_ao2_object(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger);
#endif /* ASTOBJ2_PRIVATE_H_ */

View File

@ -543,49 +543,29 @@ static void rb_rotate_right(struct ao2_container_rbtree *self, struct rbtree_nod
child->right = node;
}
/*!
* \internal
* \brief Create an empty copy of this container.
* \since 12.0.0
*
* \param self Container to operate upon.
*
* \retval empty-clone-container on success.
* \retval NULL on error.
*/
static struct ao2_container *rb_ao2_alloc_empty_clone(struct ao2_container_rbtree *self)
{
if (!is_ao2_object(self)) {
return NULL;
}
return ao2_t_container_alloc_rbtree(ao2_options_get(self), self->common.options,
self->common.sort_fn, self->common.cmp_fn, "Clone rbtree container");
}
/*!
* \internal
* \brief Create an empty copy of this container. (Debug version)
* \since 12.0.0
* \since 14.0.0
*
* \param self Container to operate upon.
* \param tag used for debugging.
* \param file Debug file name invoked from
* \param line Debug line invoked from
* \param func Debug function name invoked from
* \param ref_debug TRUE if to output a debug reference message.
*
* \retval empty-clone-container on success.
* \retval NULL on error.
*/
static struct ao2_container *rb_ao2_alloc_empty_clone_debug(struct ao2_container_rbtree *self, const char *tag, const char *file, int line, const char *func, int ref_debug)
static struct ao2_container *rb_ao2_alloc_empty_clone(struct ao2_container_rbtree *self,
const char *tag, const char *file, int line, const char *func)
{
if (!is_ao2_object(self)) {
if (!__is_ao2_object(self, file, line, func)) {
return NULL;
}
return __ao2_container_alloc_rbtree_debug(ao2_options_get(self), self->common.options,
self->common.sort_fn, self->common.cmp_fn, tag, file, line, func, ref_debug);
return __ao2_container_alloc_rbtree(ao2_options_get(self), self->common.options,
self->common.sort_fn, self->common.cmp_fn, tag, file, line, func);
}
/*!
@ -925,16 +905,12 @@ static struct rbtree_node *rb_ao2_new_node(struct ao2_container_rbtree *self, vo
{
struct rbtree_node *node;
node = __ao2_alloc(sizeof(*node), rb_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
node = ao2_t_alloc_options(sizeof(*node), rb_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK, NULL);
if (!node) {
return NULL;
}
if (tag) {
__ao2_ref_debug(obj_new, +1, tag, file, line, func);
} else {
ao2_t_ref(obj_new, +1, "Container node creation");
}
__ao2_ref(obj_new, +1, tag ?: "Container node creation", file, line, func);
node->common.obj = obj_new;
node->common.my_container = (struct ao2_container *) self;
@ -1337,7 +1313,7 @@ static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, s
}
/* We have the next traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
/*
* Dereferencing the prev node may result in our next node
@ -1345,7 +1321,7 @@ static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, s
* the container uses RW locks and the container was read
* locked.
*/
__ao2_ref(prev, -1);
ao2_t_ref(prev, -1, NULL);
if (node->common.obj) {
return node;
}
@ -1353,7 +1329,7 @@ static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, s
}
/* No more nodes in the container left to traverse. */
__ao2_ref(prev, -1);
ao2_t_ref(prev, -1, NULL);
return NULL;
}
@ -1636,7 +1612,7 @@ static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self,
}
/* We have the first traversal node */
__ao2_ref(node, +1);
ao2_t_ref(node, +1, NULL);
return node;
}
@ -2018,8 +1994,6 @@ static int rb_ao2_integrity(struct ao2_container_rbtree *self)
/*! rbtree container virtual method table. */
static const struct ao2_container_methods v_table_rbtree = {
.alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) rb_ao2_alloc_empty_clone,
.alloc_empty_clone_debug =
(ao2_container_alloc_empty_clone_debug_fn) rb_ao2_alloc_empty_clone_debug,
.new_node = (ao2_container_new_node_fn) rb_ao2_new_node,
.insert = (ao2_container_insert_fn) rb_ao2_insert_node,
.traverse_first = (ao2_container_find_first_fn) rb_ao2_find_first,
@ -2063,24 +2037,8 @@ static struct ao2_container *rb_ao2_container_init(struct ao2_container_rbtree *
}
struct ao2_container *__ao2_container_alloc_rbtree(unsigned int ao2_options, unsigned int container_options,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
{
struct ao2_container_rbtree *self;
if (!sort_fn) {
/* Sanity checks. */
ast_log(LOG_ERROR, "Missing sort_fn()!\n");
return NULL;
}
self = ao2_t_alloc_options(sizeof(*self), container_destruct, ao2_options,
"New rbtree container");
return rb_ao2_container_init(self, container_options, sort_fn, cmp_fn);
}
struct ao2_container *__ao2_container_alloc_rbtree_debug(unsigned int ao2_options, unsigned int container_options,
ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
const char *tag, const char *file, int line, const char *func, int ref_debug)
const char *tag, const char *file, int line, const char *func)
{
struct ao2_container_rbtree *self;
@ -2090,9 +2048,8 @@ struct ao2_container *__ao2_container_alloc_rbtree_debug(unsigned int ao2_option
return NULL;
}
self = __ao2_alloc_debug(sizeof(*self),
ref_debug ? container_destruct_debug : container_destruct, ao2_options,
tag, file, line, func, ref_debug);
self = __ao2_alloc(sizeof(*self), container_destruct, ao2_options,
tag ?: __PRETTY_FUNCTION__, file, line, func);
return rb_ao2_container_init(self, container_options, sort_fn, cmp_fn);
}

View File

@ -795,7 +795,9 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
return NULL;
}
if (!(tmp = ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor))) {
tmp = __ast_channel_internal_alloc(ast_channel_destructor, assignedids, requestor,
file, line, function);
if (!tmp) {
/* Channel structure allocation failure. */
return NULL;
}
@ -987,16 +989,14 @@ struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *ci
/* only do the minimum amount of work needed here to make a channel
* structure that can be used to expand channel vars */
#if defined(REF_DEBUG) || defined(__AST_DEBUG_MALLOC)
struct ast_channel *__ast_dummy_channel_alloc(const char *file, int line, const char *function)
#else
struct ast_channel *ast_dummy_channel_alloc(void)
#endif
{
struct ast_channel *tmp;
struct varshead *headp;
if (!(tmp = ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL))) {
tmp = __ast_channel_internal_alloc(ast_dummy_channel_destructor, NULL, NULL,
file, line, function);
if (!tmp) {
/* Dummy channel structure allocation failure. */
return NULL;
}

View File

@ -1439,15 +1439,9 @@ static int pvt_cause_cmp_fn(void *obj, void *vstr, int flags)
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *file, int line, const char *function)
{
struct ast_channel *tmp;
#if defined(REF_DEBUG)
tmp = __ao2_alloc_debug(sizeof(*tmp), destructor,
AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 1);
#elif defined(__AST_DEBUG_MALLOC)
tmp = __ao2_alloc_debug(sizeof(*tmp), destructor,
AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 0);
#else
tmp = ao2_alloc(sizeof(*tmp), destructor);
#endif
tmp = __ao2_alloc(sizeof(*tmp), destructor,
AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function);
if (!tmp) {
return NULL;

View File

@ -457,22 +457,14 @@ int ast_format_cache_set(struct ast_format *format)
return 0;
}
struct ast_format *__ast_format_cache_get(const char *name)
struct ast_format *__ast_format_cache_get(const char *name,
const char *tag, const char *file, int line, const char *func)
{
if (ast_strlen_zero(name)) {
return NULL;
}
return ao2_find(formats, name, OBJ_SEARCH_KEY);
}
struct ast_format *__ast_format_cache_get_debug(const char *name, const char *tag, const char *file, int line, const char *func)
{
if (ast_strlen_zero(name)) {
return NULL;
}
return __ao2_find_debug(formats, name, OBJ_SEARCH_KEY, S_OR(tag, "ast_format_cache_get"), file, line, func);
return __ao2_find(formats, name, OBJ_SEARCH_KEY, tag, file, line, func);
}
struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate)

View File

@ -103,25 +103,13 @@ static inline void format_cap_init(struct ast_format_cap *cap, enum ast_format_c
cap->framing = UINT_MAX;
}
struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags)
struct ast_format_cap *__ast_format_cap_alloc(enum ast_format_cap_flags flags,
const char *tag, const char *file, int line, const char *func)
{
struct ast_format_cap *cap;
cap = ao2_alloc_options(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!cap) {
return NULL;
}
format_cap_init(cap, flags);
return cap;
}
struct ast_format_cap *__ast_format_cap_alloc_debug(enum ast_format_cap_flags flags, const char *tag, const char *file, int line, const char *func)
{
struct ast_format_cap *cap;
cap = __ao2_alloc_debug(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(tag, "ast_format_cap_alloc"), file, line, func, 1);
cap = __ao2_alloc(sizeof(*cap), format_cap_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK,
tag, file, line, func);
if (!cap) {
return NULL;
}
@ -187,26 +175,7 @@ static int format_in_format_cap(struct ast_format_cap *cap, struct ast_format *f
return 0;
}
int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
{
struct format_cap_framed *framed;
ast_assert(format != NULL);
if (format_in_format_cap(cap, format)) {
return 0;
}
framed = ao2_alloc_options(sizeof(*framed), format_cap_framed_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!framed) {
return -1;
}
framed->format = ao2_bump(format);
return format_cap_framed_init(framed, cap, format, framing);
}
int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
int __ast_format_cap_append(struct ast_format_cap *cap, struct ast_format *format, unsigned int framing, const char *tag, const char *file, int line, const char *func)
{
struct format_cap_framed *framed;
@ -221,7 +190,7 @@ int __ast_format_cap_append_debug(struct ast_format_cap *cap, struct ast_format
return -1;
}
__ao2_ref_debug(format, +1, S_OR(tag, "ast_format_cap_append"), file, line, func);
__ao2_ref(format, +1, tag, file, line, func);
framed->format = format;
return format_cap_framed_init(framed, cap, format, framing);

View File

@ -122,10 +122,8 @@ static int modules_loaded;
struct ast_module {
const struct ast_module_info *info;
#ifdef REF_DEBUG
/* Used to get module references into REF_DEBUG logs */
/* Used to get module references into refs log */
void *ref_debug;
#endif
void *lib; /* the shared lib, or NULL if embedded */
int usecount; /* the number of 'users' currently in this module */
struct module_user_list users; /* the list of users in the module */
@ -199,9 +197,9 @@ void ast_module_register(const struct ast_module_info *info)
ast_debug(5, "Registering module %s\n", info->name);
mod->info = info;
#ifdef REF_DEBUG
mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
#endif
if (ast_opt_ref_debug) {
mod->ref_debug = ao2_t_alloc(0, NULL, info->name);
}
AST_LIST_HEAD_INIT(&mod->users);
/* during startup, before the loader has been initialized,
@ -248,9 +246,7 @@ void ast_module_unregister(const struct ast_module_info *info)
if (mod) {
ast_debug(5, "Unregistering module %s\n", info->name);
AST_LIST_HEAD_DESTROY(&mod->users);
#ifdef REF_DEBUG
ao2_cleanup(mod->ref_debug);
#endif
ast_free(mod);
}
}
@ -270,9 +266,9 @@ struct ast_module_user *__ast_module_user_add(struct ast_module *mod, struct ast
AST_LIST_INSERT_HEAD(&mod->users, u, entry);
AST_LIST_UNLOCK(&mod->users);
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, +1);
#endif
if (mod->ref_debug) {
ao2_ref(mod->ref_debug, +1);
}
ast_atomic_fetchadd_int(&mod->usecount, +1);
@ -298,9 +294,9 @@ void __ast_module_user_remove(struct ast_module *mod, struct ast_module_user *u)
return;
}
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, -1);
#endif
if (mod->ref_debug) {
ao2_ref(mod->ref_debug, -1);
}
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_free(u);
@ -318,9 +314,9 @@ void __ast_module_user_hangup_all(struct ast_module *mod)
ast_softhangup(u->chan, AST_SOFTHANGUP_APPUNLOAD);
}
#ifdef REF_DEBUG
ao2_ref(mod->ref_debug, -1);
#endif
if (mod->ref_debug) {
ao2_ref(mod->ref_debug, -1);
}
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_free(u);
@ -641,9 +637,7 @@ void ast_module_shutdown(void)
mod->info->unload();
}
AST_LIST_HEAD_DESTROY(&mod->users);
#ifdef REF_DEBUG
ao2_cleanup(mod->ref_debug);
#endif
ast_free(mod);
somethingchanged = 1;
}
@ -1477,9 +1471,9 @@ struct ast_module *__ast_module_ref(struct ast_module *mod, const char *file, in
return NULL;
}
#ifdef REF_DEBUG
__ao2_ref_debug(mod->ref_debug, +1, "", file, line, func);
#endif
if (mod->ref_debug) {
__ao2_ref(mod->ref_debug, +1, "", file, line, func);
}
ast_atomic_fetchadd_int(&mod->usecount, +1);
ast_update_use_count();
@ -1503,9 +1497,9 @@ void __ast_module_unref(struct ast_module *mod, const char *file, int line, cons
return;
}
#ifdef REF_DEBUG
__ao2_ref_debug(mod->ref_debug, -1, "", file, line, func);
#endif
if (mod->ref_debug) {
__ao2_ref(mod->ref_debug, -1, "", file, line, func);
}
ast_atomic_fetchadd_int(&mod->usecount, -1);
ast_update_use_count();

View File

@ -210,7 +210,7 @@ static int reload(void);
#define mohclass_ref(class,string) (ao2_t_ref((class), +1, (string)), class)
#ifndef REF_DEBUG
#ifndef AST_DEVMODE
#define mohclass_unref(class,string) ({ ao2_t_ref((class), -1, (string)); (struct mohclass *) NULL; })
#else
#define mohclass_unref(class,string) _mohclass_unref(class, string, __FILE__,__LINE__,__PRETTY_FUNCTION__)
@ -219,14 +219,14 @@ static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag,
struct mohclass *dup = ao2_callback(mohclasses, OBJ_POINTER, ao2_match_by_addr, class);
if (dup) {
if (__ao2_ref_debug(dup, -1, (char *) tag, (char *) file, line, funcname) == 2) {
if (__ao2_ref(dup, -1, tag, file, line, funcname) == 2) {
ast_log(LOG_WARNING, "Attempt to unref mohclass %p (%s) when only 1 ref remained, and class is still in a container! (at %s:%d (%s))\n",
class, class->name, file, line, funcname);
} else {
ao2_ref(class, -1);
}
} else {
__ao2_ref_debug(class, -1, (char *) tag, (char *) file, line, funcname);
__ao2_ref(class, -1, tag, file, line, funcname);
}
return NULL;
}
@ -877,12 +877,8 @@ static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, co
ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
#ifdef REF_DEBUG
moh = __ao2_find_debug(mohclasses, &tmp_class, flags,
moh = __ao2_find(mohclasses, &tmp_class, flags,
"get_mohbyname", file, lineno, funcname);
#else
moh = __ao2_find(mohclasses, &tmp_class, flags);
#endif
if (!moh && warn) {
ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
@ -1373,17 +1369,9 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char
{
struct mohclass *class;
if ((class =
#ifdef REF_DEBUG
__ao2_alloc_debug(sizeof(*class), moh_class_destructor,
AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 1)
#elif defined(__AST_DEBUG_MALLOC)
__ao2_alloc_debug(sizeof(*class), moh_class_destructor,
AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 0)
#else
ao2_alloc(sizeof(*class), moh_class_destructor)
#endif
)) {
class = __ao2_alloc(sizeof(*class), moh_class_destructor, AO2_ALLOC_OPT_LOCK_MUTEX,
"Allocating new moh class", file, line, funcname);
if (class) {
class->format = ao2_bump(ast_format_slin);
class->srcfd = -1;
}