[Asterisk-code-review] RFC: ao2 reference storage location logging. (asterisk[master])

Corey Farrell asteriskteam at digium.com
Sat Jul 2 15:15:08 CDT 2016


Corey Farrell has uploaded a new change for review.

  https://gerrit.asterisk.org/3141

Change subject: RFC: ao2 reference storage location logging.
......................................................................

RFC: ao2 reference storage location logging.

This is not ready to be committed.  For now the goal is to see if this
change will be received, and get feedback on the changes to astobj2.h.
This change allows ao2_ref/ao2_alloc to record REF_DEBUG information
that allows refcounter.py to find matching ref + unref and filter them
out of the results.  This can be very helpful with certain objects like
formats that are long lived and widely used.

For initial reviews please focus on API's added to astobj2.h.  I want
to determine a good API to be used for associating the storage location
with REF_DEBUG output.  Other changes are in place to show a working
example.  This has been tested using tests/bridge/hold_redirect.  No
leaks are fixed, but the output from refcounter.py is reduced by 66% due
to matching of some ref/unref for leaked objects. See JIRA for example
output.

As a bonus this commit records the size of AO2 allocations to the
REFS_DEBUG log.  Currently this is just printed in the output from
refcounter.py, but in the future it could be used to detect indirect
reference leaks - where one object leaks and holds a reference to
another.

ASTERISK-26171

Change-Id: Iacb0a51cefaa98c83eab18aa2b7d18850bb33951
---
M contrib/scripts/refcounter.py
M include/asterisk/astobj2.h
M include/asterisk/codec.h
M include/asterisk/format.h
M include/asterisk/format_cache.h
M include/asterisk/format_cap.h
M include/asterisk/stasis.h
M include/asterisk/utils.h
M main/astobj2.c
M main/astobj2_container.c
M main/codec.c
M main/format.c
M main/format_cache.c
M main/format_cap.c
M main/frame.c
M main/rtp_engine.c
M main/stasis.c
M main/stasis_cache.c
M main/stasis_cache_pattern.c
M main/stasis_message.c
M main/threadpool.c
M main/translate.c
22 files changed, 324 insertions(+), 215 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/41/3141/1

diff --git a/contrib/scripts/refcounter.py b/contrib/scripts/refcounter.py
index 1f4b375..e8d9c8a 100755
--- a/contrib/scripts/refcounter.py
+++ b/contrib/scripts/refcounter.py
@@ -24,7 +24,7 @@
 from optparse import OptionParser
 
 
-def parse_line(line):
+def parse_line(line, processpointers):
     """Parse out a line into its constituent parts.
 
     Keyword Arguments:
@@ -33,8 +33,8 @@
     Returns:
     A dictionary containing the options, or None
     """
-    tokens = line.strip().split(',', 7)
-    if len(tokens) < 8:
+    tokens = line.strip().split(',', 8)
+    if len(tokens) < 9:
         print "ERROR: ref debug line '%s' contains fewer tokens than " \
               "expected: %d" % (line.strip(), len(tokens))
         return None
@@ -46,9 +46,30 @@
                       'line': tokens[4],
                       'function': tokens[5],
                       'state': tokens[6],
-                      'tag': tokens[7],
+                      'ptr': tokens[7],
+                      'tag': tokens[8],
                       }
-    return processed_line
+
+    line_obj = {
+        'addr': processed_line['addr'],
+        'delta': processed_line['delta'],
+        'tag': processed_line['tag'],
+        'ptr': processed_line['ptr'],
+        'state': processed_line['state'],
+        'text': "[%s] %s:%s %s" % (processed_line['thread_id'],
+                                   processed_line['file'],
+                                   processed_line['line'],
+                                   processed_line['function']),
+        'is_ptr': False
+    }
+
+    if line_obj['ptr'] != '(nil)':
+        line_obj['is_ptr'] = processpointers
+        line_obj['ptr'] = ' ptr:%s' % line_obj['ptr']
+    else:
+        line_obj['ptr'] = ''
+
+    return line_obj
 
 
 def process_file(options):
@@ -74,71 +95,69 @@
     leaked_objects = []
     skewed_objects = []
     current_objects = {}
+    byptr = {}
     filename = options.filepath
 
     with open(filename, 'r') as ref_file:
-        for line in ref_file:
-            parsed_line = parse_line(line)
-            if not parsed_line:
+        for txtline in ref_file:
+            line = parsed_line = parse_line(txtline, options.processpointers)
+            if not line:
                 continue
 
             invalid = False
-            obj = parsed_line['addr']
+            obj = line['addr']
 
             if obj not in current_objects:
-                current_objects[obj] = {'log': [], 'curcount': 1}
-                if 'constructor' in parsed_line['state']:
+                currobj = {'log': [], 'curcount': 1, 'size': "unknown"}
+                current_objects[obj] = currobj
+                if 'constructor' in line['state']:
+                    currobj['size'] = line['state'].split("**")[2]
                     # This is the normal expected case
                     pass
-                elif 'invalid' in parsed_line['state']:
+                elif 'invalid' in line['state']:
                     invalid = True
-                    current_objects[obj]['curcount'] = 0
+                    currobj['curcount'] = 0
                     if options.invalid:
-                        invalid_objects.append((obj, current_objects[obj]))
-                elif 'destructor' in parsed_line['state']:
-                    current_objects[obj]['curcount'] = 0
+                        invalid_objects.append((obj, currobj))
+                elif 'destructor' in line['state']:
+                    currobj['curcount'] = 0
                     if options.skewed:
-                        skewed_objects.append((obj, current_objects[obj]))
+                        skewed_objects.append((obj, currobj))
                 else:
-                    current_objects[obj]['curcount'] = int(
-                        parsed_line['state'])
+                    currobj['curcount'] = int(line['state'])
                     if options.skewed:
-                        skewed_objects.append((obj, current_objects[obj]))
+                        skewed_objects.append((obj, currobj))
             else:
-                current_objects[obj]['curcount'] += int(parsed_line['delta'])
+                currobj = current_objects[obj]
+                currobj['curcount'] += int(line['delta'])
 
-            current_objects[obj]['log'].append(
-                "[%s] %s:%s %s: %s %s - [%s]" % (
-                    parsed_line['thread_id'],
-                    parsed_line['file'],
-                    parsed_line['line'],
-                    parsed_line['function'],
-                    parsed_line['delta'],
-                    parsed_line['tag'],
-                    parsed_line['state']))
+            if line['is_ptr']:
+                ptr = line['ptr']
+                if line['delta'] == "-1":
+                    if ptr in byptr and byptr[ptr]['addr'] == obj:
+                        currobj['log'].remove(byptr[ptr])
+                        del byptr[ptr]
+                    else:
+                        currobj['log'].append(line)
+                elif line['delta'] == "+1":
+                    byptr[ptr] = line
+                    currobj['log'].append(line)
+            else:
+                currobj['log'].append(line)
 
             # It is possible for curcount to go below zero if someone
             # unrefs an object by two or more when there aren't that
             # many refs remaining.  This condition abnormally finishes
             # the object.
-            if current_objects[obj]['curcount'] <= 0:
-                if current_objects[obj]['curcount'] < 0:
-                    current_objects[obj]['log'].append(
-                        "[%s] %s:%s %s: %s %s - [%s]" % (
-                            parsed_line['thread_id'],
-                            parsed_line['file'],
-                            parsed_line['line'],
-                            parsed_line['function'],
-                            "+0",
-                            "Object abnormally finalized",
-                            "**implied destructor**"))
+            if currobj['curcount'] <= 0:
+                if currobj['curcount'] < 0:
                     # Highlight the abnormally finished object in the
                     # invalid section as well as reporting it in the normal
                     # finished section.
                     if options.invalid:
-                        invalid_objects.append((obj, current_objects[obj]))
+                        invalid_objects.append((obj, currobj))
                 if not invalid and options.normal:
-                    finished_objects.append((obj, current_objects[obj]))
+                    finished_objects.append((obj, currobj))
                 del current_objects[obj]
 
     if options.leaks:
@@ -159,9 +178,11 @@
     print "======== %s Objects ========" % prefix
     print "\n"
     for obj in objects:
-        print "==== %s Object %s history ====" % (prefix, obj[0])
+        print "==== %s Object %s (%s bytes) history ====" % (prefix, obj[0], obj[1]['size'])
+        current_count = 0;
         for line in obj[1]['log']:
-            print line
+            print "%s: %s%s %s - [%d]" % (line['text'], line['delta'], line['ptr'], line['tag'], current_count)
+            current_count += int(line['delta'])
         print "\n"
 
 
@@ -193,6 +214,9 @@
                       dest="skewed", default=True,
                       help="If specified, don't output objects with a "
                            "skewed lifetime")
+    parser.add_option("--ignorepointers", action="store_false",
+                      dest="processpointers", default=True,
+                      help="If specified, don't check for matching pointers in unrefs")
 
     (options, args) = parser.parse_args(argv)
 
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h
index 0472c1b..03a6268 100644
--- a/include/asterisk/astobj2.h
+++ b/include/asterisk/astobj2.h
@@ -403,8 +403,15 @@
 #define ao2_alloc(data_size, destructor_fn) \
 	__ao2_alloc((data_size), (destructor_fn), AO2_ALLOC_OPT_LOCK_MUTEX, "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-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;
+void *__ao2_alloc_full(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
+	attribute_warn_unused_result;
+#define __ao2_alloc(data_size, destructor_fn, options, tag, file, line, func) \
+	__ao2_alloc_full((data_size), (destructor_fn), (options), (tag), NULL, (file), (line), (func))
+
+#define ao2_alloc_full(data_size, destructor_fn, options, tag, debugstorage) \
+	__ao2_alloc_full((data_size), (destructor_fn), (options), (tag), (debugstorage), \
+		__FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 /*! @} */
 
@@ -453,18 +460,61 @@
  * \param obj AO2 object to bump the refcount on.
  * \retval The given \a obj pointer.
  */
-#define ao2_t_bump(obj, tag)						\
+#define ao2_bump_full(obj, tag, debugstorage) \
 	({							\
 		typeof(obj) __obj_ ## __LINE__ = (obj);		\
 		if (__obj_ ## __LINE__) {			\
-			ao2_t_ref(__obj_ ## __LINE__, +1, (tag));	\
+			ao2_ref_full(__obj_ ## __LINE__, +1, (tag), (debugstorage));	\
 		}						\
 		__obj_ ## __LINE__;				\
 	})
+#define ao2_t_bump(obj, tag) \
+	ao2_bump_full(obj, tag, NULL)
 #define ao2_bump(obj) \
 	ao2_t_bump((obj), "")
 
-int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func);
+int __ao2_ref_full(void *o, int delta, const char *tag, void *debugstorage,
+	const char *file, int line, const char *func);
+
+#define __ao2_ref(o, delta, tag, file, line, func) \
+	__ao2_ref_full((o), (delta), (tag), NULL, (file), (line), (func))
+
+#define ao2_ref_full(o, delta, tag, debugstorage) \
+	__ao2_ref_full((o), (delta), (tag) ?: "", (debugstorage), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define ao2_s_alloc(storage, data_size, destructor_fn) \
+	{ \
+		typeof(storage) __dst ## __LINE__ = (storage); \
+		*__dst ## __LINE__ = ao2_alloc_full((data_size), (destructor_fn), \
+			AO2_ALLOC_OPT_LOCK_MUTEX, "", __dst ## __LINE__); \
+	}
+
+#define ao2_s_set(storage, obj) \
+	{ \
+		typeof(storage) __dst ## __LINE__ = (storage); \
+		*__dst ## __LINE__ = obj; \
+		if (*__dst ## __LINE__) { \
+			ao2_ref_full(*__dst ## __LINE__, +1, "", __dst ## __LINE__); \
+		} \
+	}
+
+#define ao2_s_replace(storage, newval) \
+	{ \
+		typeof(storage) __dst ## __LINE__ = (storage); \
+		typeof(newval) __src ## __LINE__ = (newval); \
+		if (*__dst ## __LINE__ != __src ## __LINE__) { \
+			ao2_s_cleanup(__dst ## __LINE__); \
+			ao2_s_set(__dst ## __LINE__, __src ## __LINE__); \
+		} \
+	}
+
+#define ao2_s_cleanup(storage) \
+	{ \
+		typeof(storage) __dst ## __LINE__ = (storage); \
+		if (*__dst ## __LINE__) { \
+			ao2_ref_full(*__dst ## __LINE__, -1, "", __dst ## __LINE__); \
+		} \
+	} \
 
 /*!
  * \since 12.4.0
@@ -889,11 +939,11 @@
  * \retval NULL if no object available.
  */
 #define ao2_t_global_obj_ref(holder, tag)	\
-	__ao2_global_obj_ref(&holder, (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
+	__ao2_global_obj_ref(&holder, (tag), NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 #define ao2_global_obj_ref(holder)	\
-	__ao2_global_obj_ref(&holder, "", __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
+	__ao2_global_obj_ref(&holder, "", NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder)
 
-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;
+void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, void *debugstorage, const char *file, int line, const char *func, const char *name) attribute_warn_unused_result;
 
 
 /*!
@@ -1703,9 +1753,12 @@
 #define ao2_callback(c, flags, cb_fn, arg) \
 	__ao2_callback((c), (flags), (cb_fn), (arg), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-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,
+void *__ao2_callback_full(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_fn *cb_fn, void *arg, const char *tag, void *debugstorage, const char *file, int line,
 	const char *func);
+
+#define __ao2_callback(c, flags, cb_fn, arg, tag, file, line, func) \
+	__ao2_callback_full((c), (flags), (cb_fn), (arg), (tag), NULL, (file), (line), (func))
 
 /*! @} */
 
@@ -1730,9 +1783,12 @@
 #define ao2_callback_data(container, flags, cb_fn, arg, data) \
 	__ao2_callback_data((container), (flags), (cb_fn), (arg), (data), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-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_full(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, void *debugstorage,
+	const char *file, int line, const char *func);
+
+#define __ao2_callback_data(c, flags, cb_fn, arg, data, tag, file, line, func) \
+	__ao2_callback_data_full((c), (flags), (cb_fn), (arg), (data), (tag), NULL, (file), (line), (func))
 
 /*! ao2_find() is a short hand for ao2_callback(c, flags, c->cmp_fn, arg)
  * XXX possibly change order of arguments ?
@@ -1743,8 +1799,13 @@
 #define ao2_find(container, arg, flags) \
 	__ao2_find((container), (arg), (flags), "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-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_full(struct ao2_container *c, const void *arg, enum search_flags flags,
+	const char *tag, void *debugstorage, const char *file, int line, const char *func);
+#define ao2_find_full(container, arg, flags, tag, debugstorage) \
+	__ao2_find_full((container), (arg), (flags), (tag), (debugstorage), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+#define __ao2_find(container, arg, flags, tag, file, line, func) \
+	__ao2_find_full((container), (arg), (flags), (tag), NULL, (file), (line), (func))
 
 /*! \brief
  *
diff --git a/include/asterisk/codec.h b/include/asterisk/codec.h
index 3873324..0678177 100644
--- a/include/asterisk/codec.h
+++ b/include/asterisk/codec.h
@@ -131,7 +131,10 @@
  * \note The returned codec is reference counted and ao2_ref or ao2_cleanup
  * must be used to release the reference.
  */
-struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate);
+#define ast_codec_get(name, type, sample_rate) \
+	__ast_codec_get((name), (type), (sample_rate), NULL)
+struct ast_codec *__ast_codec_get(const char *name, enum ast_media_type type,
+	unsigned int sample_rate, void *debugstorage);
 
 /*!
  * \brief Retrieve a codec given the unique identifier
@@ -146,7 +149,8 @@
  * \note The returned codec is reference counted and ao2_ref or ao2_cleanup
  * must be used to release the reference.
  */
-struct ast_codec *ast_codec_get_by_id(int id);
+#define ast_codec_get_by_id(id) __ast_codec_get_by_id((id), NULL)
+struct ast_codec *__ast_codec_get_by_id(int id, void *debugstorage);
 
 /*!
  * \brief Retrieve the current maximum identifier for codec iteration
diff --git a/include/asterisk/format.h b/include/asterisk/format.h
index a5ca038..97011a8 100644
--- a/include/asterisk/format.h
+++ b/include/asterisk/format.h
@@ -153,7 +153,8 @@
  * \note The format is returned with reference count incremented. It must be released using
  * ao2_ref or ao2_cleanup.
  */
-struct ast_format *ast_format_create(struct ast_codec *codec);
+#define ast_format_create(codec) __ast_format_create(codec, NULL)
+struct ast_format *__ast_format_create(struct ast_codec *codec, void *debugstorage);
 
 /*!
  * \brief Create a new media format with a specific name
@@ -171,7 +172,9 @@
  * \retval non-NULL success
  * \retval NULL failure
  */
-struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec);
+#define ast_format_create_named(format_name, codec) __ast_format_create_named((format_name), (codec), NULL)
+struct ast_format *__ast_format_create_named(const char *format_name, struct ast_codec *codec,
+	void *debugstorage);
 
 /*!
  * \brief Clone an existing media format so it can be modified
@@ -307,7 +310,8 @@
  *
  * \note The reference count of the returned codec is increased by 1 and must be decremented
  */
-struct ast_codec *ast_format_get_codec(const struct ast_format *format);
+#define ast_format_get_codec(format) __ast_format_get_codec((format), NULL)
+struct ast_codec *__ast_format_get_codec(const struct ast_format *format, void *debugstorage);
 
 /*!
  * \brief Get the codec identifier associated with a format
diff --git a/include/asterisk/format_cache.h b/include/asterisk/format_cache.h
index 64e53b9..2c3d734 100644
--- a/include/asterisk/format_cache.h
+++ b/include/asterisk/format_cache.h
@@ -253,12 +253,15 @@
  * dropped using ao2_ref or ao2_cleanup.
  */
 struct ast_format *__ast_format_cache_get(const char *name,
-	const char *tag, const char *file, int line, const char *func);
+	const char *tag, void *debugstorage, const char *file, int line, const char *func);
+
+#define ast_format_cache_get_full(name, tag, debugstorage) \
+	__ast_format_cache_get((name), (tag), (debugstorage), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
 #define ast_format_cache_get(name) \
-	__ast_format_cache_get((name), "ast_format_cache_get", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+	ast_format_cache_get_full((name), "ast_format_cache_get", NULL)
 #define ast_t_format_cache_get(name, tag) \
-	__ast_format_cache_get((name), (tag), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+	ast_format_cache_get_full((name), (tag), NULL)
 
 
 /*!
diff --git a/include/asterisk/format_cap.h b/include/asterisk/format_cap.h
index 8b69e08..7b44a75 100644
--- a/include/asterisk/format_cap.h
+++ b/include/asterisk/format_cap.h
@@ -187,7 +187,10 @@
  * \note The reference count of the returned format is increased. It must be released using ao2_ref
  * or ao2_cleanup.
  */
-struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position);
+#define ast_format_cap_get_format(cap, position) \
+	__ast_format_cap_get_format((cap), (position), NULL)
+struct ast_format *__ast_format_cap_get_format(const struct ast_format_cap *cap, int position,
+	void *debugstorage);
 
 /*!
  * \brief Get the most preferred format for a particular media type
diff --git a/include/asterisk/stasis.h b/include/asterisk/stasis.h
index 62ed1ed..6f22d7e 100644
--- a/include/asterisk/stasis.h
+++ b/include/asterisk/stasis.h
@@ -470,7 +470,8 @@
  * \return \c NULL on error.
  * \since 12
  */
-struct stasis_topic *stasis_topic_create(const char *name);
+#define stasis_topic_create(name) __stasis_topic_create((name), NULL);
+struct stasis_topic *__stasis_topic_create(const char *name, void *debugstorage);
 
 /*!
  * \brief Return the name of a topic.
@@ -960,8 +961,10 @@
  * \return \c NULL on error
  * \since 12
  */
-struct stasis_caching_topic *stasis_caching_topic_create(
-	struct stasis_topic *original_topic, struct stasis_cache *cache);
+#define stasis_caching_topic_create(original_topic, cache) \
+	__stasis_caching_topic_create((original_topic), (cache), NULL)
+struct stasis_caching_topic *__stasis_caching_topic_create(
+	struct stasis_topic *original_topic, struct stasis_cache *cache, void *debugstorage);
 
 /*!
  * \brief Unsubscribes a caching topic from its upstream topic.
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index c7a4737..8887bda 100644
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -1039,6 +1039,11 @@
     __block vartype varname = initval;                                                                           \
     _raii_cleanup_ ## varname = ^{ {(void)dtor(varname);} }
 
+#define RAII_AO2_S(vartype, varname, initval)                                                              \
+    _raii_cleanup_block_t _raii_cleanup_ ## varname __attribute__((cleanup(_raii_cleanup_block),unused)) = NULL; \
+    __block vartype varname = initval;                                                                           \
+    _raii_cleanup_ ## varname = ^{ {(void)ao2_s_cleanup(&(varname));} }
+
 #elif defined(__GNUC__)
 
 #define RAII_VAR(vartype, varname, initval, dtor)                              \
@@ -1046,10 +1051,19 @@
     void _dtor_ ## varname (vartype * v) { dtor(*v); }                         \
     vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
 
+#define RAII_AO2_S(vartype, varname, initval)                                  \
+    auto void _dtor_ ## varname (vartype * v);                                 \
+    void _dtor_ ## varname (vartype * v) { ao2_s_cleanup(v); }                 \
+    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
+
 #else
     #error "Cannot compile Asterisk: unknown and unsupported compiler."
 #endif /* #if __GNUC__ */
 
+#define RAII_AO2_S_GLOBAL(vartype, varname, holder) \
+	RAII_AO2_S(vartype, varname, \
+		__ao2_global_obj_ref((&holder), "", &varname, __FILE__, __LINE__, __PRETTY_FUNCTION__, #holder))
+
 /*!
  * \brief Asterisk wrapper around crypt(3).
  *
diff --git a/main/astobj2.c b/main/astobj2.c
index ed91577..0d65a2b 100644
--- a/main/astobj2.c
+++ b/main/astobj2.c
@@ -435,8 +435,8 @@
 	return NULL;
 }
 
-int __ao2_ref(void *user_data, int delta,
-	const char *tag, const char *file, int line, const char *func)
+int __ao2_ref_full(void *user_data, int delta,
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
 {
 	struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
 	struct astobj2_lock *obj_mutex;
@@ -447,8 +447,8 @@
 
 	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 ?: "");
+			fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%p,%s\n",
+				user_data, delta, ast_get_tid(), file, line, func, debugstorage, tag ?: "");
 			fflush(ref_log);
 		}
 		ast_assert(0);
@@ -500,9 +500,9 @@
 	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,
+			fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%p,%s\n", user_data,
 				(delta < 0 ? "" : "+"), delta, ast_get_tid(),
-				file, line, func, ret, tag);
+				file, line, func, ret, debugstorage, tag);
 			fflush(ref_log);
 		}
 		return ret;
@@ -514,8 +514,8 @@
 			"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 ?: "");
+			fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%p,%s\n",
+				user_data, delta, ast_get_tid(), file, line, func, debugstorage, tag ?: "");
 			fflush(ref_log);
 		}
 		ast_assert(0);
@@ -559,8 +559,8 @@
 	}
 
 	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);
+		fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%p,%s\n",
+			user_data, delta, ast_get_tid(), file, line, func, debugstorage, tag);
 		fflush(ref_log);
 	}
 
@@ -581,8 +581,8 @@
 	}
 }
 
-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)
+void *__ao2_alloc_full(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
 {
 	/* allocation */
 	struct astobj2 *obj;
@@ -646,8 +646,8 @@
 #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);
+		fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**%zu**,%p,%s\n",
+			EXTERNAL_OBJ(obj), ast_get_tid(), file, line, func, data_size, debugstorage, tag);
 		fflush(ref_log);
 	}
 
@@ -729,7 +729,7 @@
 	return 0;
 }
 
-void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
+void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, void *debugstorage, const char *file, int line, const char *func, const char *name)
 {
 	void *obj;
 
@@ -748,7 +748,7 @@
 
 	obj = holder->obj;
 	if (obj) {
-		__ao2_ref(obj, +1, tag, file, line, func);
+		__ao2_ref_full(obj, +1, tag, debugstorage, file, line, func);
 	}
 
 	__ast_rwlock_unlock(file, line, func, &holder->lock, name);
diff --git a/main/astobj2_container.c b/main/astobj2_container.c
index c00da9f..7ac7547 100644
--- a/main/astobj2_container.c
+++ b/main/astobj2_container.c
@@ -229,7 +229,7 @@
  */
 static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags flags,
 	void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
-	const char *tag, const char *file, int line, const char *func)
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
 {
 	void *ret;
 	ao2_callback_fn *cb_default = NULL;
@@ -358,7 +358,7 @@
 						 * Bump the ref count since we are not going to unlink and
 						 * transfer the container's object ref to the returned object.
 						 */
-						__ao2_ref(ret, 1, tag ?: "Traversal found object", file, line, func);
+						__ao2_ref_full(ret, 1, tag ?: "Traversal found object", debugstorage, file, line, func);
 					}
 				}
 			}
@@ -403,25 +403,25 @@
 	}
 }
 
-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_full(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_fn *cb_fn, void *arg, const char *tag, void *debugstorage,
+	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);
+	return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, debugstorage, 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, const char *tag, const char *file,
-	int line, const char *func)
+void *__ao2_callback_data_full(struct ao2_container *c, enum search_flags flags,
+	ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, void *debugstorage,
+	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);
+	return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, debugstorage, file, line, func);
 }
 
 /*!
  * the find function just invokes the default callback with some reasonable 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_full(struct ao2_container *c, const void *arg, enum search_flags flags,
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
 {
 	void *arged = (void *) arg;/* Done to avoid compiler const warning */
 
@@ -430,7 +430,7 @@
 		ast_assert(0);
 		return NULL;
 	}
-	return __ao2_callback(c, flags, c->cmp_fn, arged, tag, file, line, func);
+	return __ao2_callback_full(c, flags, c->cmp_fn, arged, tag, debugstorage, file, line, func);
 }
 
 /*!
diff --git a/main/codec.c b/main/codec.c
index 49356a2..4630b43 100644
--- a/main/codec.c
+++ b/main/codec.c
@@ -317,8 +317,8 @@
 		return -1;
 	}
 
-	codec_new = ao2_t_alloc_options(sizeof(*codec_new), codec_dtor,
-		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
+	codec_new = ao2_alloc_full(sizeof(*codec_new), codec_dtor,
+		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""), &codec_new);
 	if (!codec_new) {
 		ast_log(LOG_ERROR, "Could not allocate a codec with name '%s' of type '%s' and sample rate '%u'\n",
 			codec->name, ast_codec_media_type2str(codec->type), codec->sample_rate);
@@ -328,7 +328,7 @@
 	codec_new->format_name = format_name;
 	codec_new->external.id = codec_id++;
 
-	ao2_link_flags(codecs, codec_new, OBJ_NOLOCK);
+	ao2_t_link_flags(codecs, codec_new, OBJ_NOLOCK, S_OR(codec->description, ""));
 
 	/* Once registered a codec can not be unregistered, and the module must persist until shutdown */
 	ast_module_shutdown_ref(mod);
@@ -336,12 +336,13 @@
 	ast_verb(2, "Registered '%s' codec '%s' at sample rate '%u' with id '%u'\n",
 		ast_codec_media_type2str(codec->type), codec->name, codec->sample_rate, codec_new->external.id);
 
-	ao2_ref(codec_new, -1);
+	ao2_s_cleanup(&codec_new);
 
 	return 0;
 }
 
-struct ast_codec *ast_codec_get(const char *name, enum ast_media_type type, unsigned int sample_rate)
+struct ast_codec *__ast_codec_get(const char *name, enum ast_media_type type,
+	unsigned int sample_rate, void *debugstorage)
 {
 	struct ast_codec codec = {
 		.name = name,
@@ -349,12 +350,13 @@
 		.sample_rate = sample_rate,
 	};
 
-	return ao2_find(codecs, &codec, OBJ_SEARCH_OBJECT);
+	return ao2_find_full(codecs, &codec, OBJ_SEARCH_OBJECT, "", debugstorage);
 }
 
-struct ast_codec *ast_codec_get_by_id(int id)
+struct ast_codec *__ast_codec_get_by_id(int id, void *debugstorage)
 {
-	return ao2_callback(codecs, 0, codec_id_cmp, &id);
+	return __ao2_callback_full(codecs, 0, codec_id_cmp, &id, "",
+		debugstorage, __FILE__, __LINE__, __PRETTY_FUNCTION__);
 }
 
 int ast_codec_get_max(void)
diff --git a/main/format.c b/main/format.c
index cc9ac45..cb25b78 100644
--- a/main/format.c
+++ b/main/format.c
@@ -186,21 +186,22 @@
 		format->interface->format_destroy(format);
 	}
 
-	ao2_cleanup(format->codec);
+	ao2_s_cleanup(&format->codec);
 }
 
-struct ast_format *ast_format_create_named(const char *format_name, struct ast_codec *codec)
+struct ast_format *__ast_format_create_named(const char *format_name, struct ast_codec *codec,
+	void *debugstorage)
 {
 	struct ast_format *format;
 	struct format_interface *format_interface;
 
-	format = ao2_t_alloc_options(sizeof(*format), format_destroy,
-		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""));
+	format = ao2_alloc_full(sizeof(*format), format_destroy,
+		AO2_ALLOC_OPT_LOCK_NOLOCK, S_OR(codec->description, ""), debugstorage);
 	if (!format) {
 		return NULL;
 	}
 	format->name = format_name;
-	format->codec = ao2_bump(codec);
+	ao2_s_set(&format->codec, codec);
 
 	format_interface = ao2_find(interfaces, codec->name, OBJ_SEARCH_KEY);
 	if (format_interface) {
@@ -227,9 +228,9 @@
 	return cloned;
 }
 
-struct ast_format *ast_format_create(struct ast_codec *codec)
+struct ast_format *__ast_format_create(struct ast_codec *codec, void *debugstorage)
 {
-	return ast_format_create_named(codec->name, codec);
+	return __ast_format_create_named(codec->name, codec, debugstorage);
 }
 
 enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
@@ -355,9 +356,9 @@
 	interface->format_generate_sdp_fmtp(format, payload, str);
 }
 
-struct ast_codec *ast_format_get_codec(const struct ast_format *format)
+struct ast_codec *__ast_format_get_codec(const struct ast_format *format, void *debugstorage)
 {
-	return ao2_bump(format->codec);
+	return ao2_bump_full(format->codec, "", debugstorage);
 }
 
 unsigned int ast_format_get_codec_id(const struct ast_format *format)
diff --git a/main/format_cache.c b/main/format_cache.c
index def795c..90bd727 100644
--- a/main/format_cache.c
+++ b/main/format_cache.c
@@ -458,13 +458,13 @@
 }
 
 struct ast_format *__ast_format_cache_get(const char *name,
-	const char *tag, const char *file, int line, const char *func)
+	const char *tag, void *debugstorage, const char *file, int line, const char *func)
 {
 	if (ast_strlen_zero(name)) {
 		return NULL;
 	}
 
-	return __ao2_find(formats, name, OBJ_SEARCH_KEY, tag, file, line, func);
+	return __ao2_find_full(formats, name, OBJ_SEARCH_KEY, tag, debugstorage, file, line, func);
 }
 
 struct ast_format *ast_format_cache_get_slin_by_rate(unsigned int rate)
diff --git a/main/format_cap.c b/main/format_cap.c
index 2b3e6cd..ca86e9b 100644
--- a/main/format_cap.c
+++ b/main/format_cap.c
@@ -145,7 +145,7 @@
 {
 	struct format_cap_framed *framed = obj;
 
-	ao2_cleanup(framed->format);
+	ao2_s_cleanup(&framed->format);
 }
 
 static inline int format_cap_framed_init(struct format_cap_framed *framed, struct ast_format_cap *cap, struct ast_format *format, unsigned int framing)
@@ -206,7 +206,7 @@
 		return -1;
 	}
 
-	__ao2_ref(format, +1, tag, file, line, func);
+	__ao2_ref_full(format, +1, tag, &framed->format, file, line, func);
 	framed->format = format;
 
 	return format_cap_framed_init(framed, cap, format, framing);
@@ -217,7 +217,7 @@
 	int id;
 
 	for (id = 1; id < ast_codec_get_max(); ++id) {
-		struct ast_codec *codec = ast_codec_get_by_id(id);
+		RAII_AO2_S(struct ast_codec *, codec, __ast_codec_get_by_id(id, &codec));
 		struct ast_codec *codec2 = NULL;
 		struct ast_format *format;
 		int res;
@@ -227,27 +227,24 @@
 		}
 
 		if ((type != AST_MEDIA_TYPE_UNKNOWN) && codec->type != type) {
-			ao2_ref(codec, -1);
 			continue;
 		}
 
-		format = ast_format_cache_get(codec->name);
+		format = ast_format_cache_get_full(codec->name, "", &format);
 
 		if (format == ast_format_none) {
-			ao2_ref(format, -1);
-			ao2_ref(codec, -1);
+			ao2_s_cleanup(&format);
 			continue;
 		}
 
 		if (format) {
-			codec2 = ast_format_get_codec(format);
+			codec2 = __ast_format_get_codec(format, &codec2);
 		}
 		if (codec != codec2) {
-			ao2_cleanup(format);
-			format = ast_format_create(codec);
+			ao2_s_cleanup(&format);
+			format = __ast_format_create(codec, &format);
 		}
-		ao2_cleanup(codec2);
-		ao2_ref(codec, -1);
+		ao2_s_cleanup(&codec2);
 
 		if (!format) {
 			return -1;
@@ -255,7 +252,7 @@
 
 		/* Use the global framing or default framing of the codec */
 		res = ast_format_cap_append(cap, format, 0);
-		ao2_ref(format, -1);
+		ao2_s_cleanup(&format);
 
 		if (res) {
 			return -1;
@@ -292,6 +289,7 @@
 		framed = AST_VECTOR_GET(&cap->preference_order, i);
 
 		if (ast_format_get_codec_id(format) == ast_format_get_codec_id(framed->format)) {
+			/* BUGBUG: tag with debugstorage */
 			ao2_t_replace(framed->format, format, "replacing with new format");
 			framed->framing = framing;
 			return 0;
@@ -363,7 +361,7 @@
 		}
 		all = strcasecmp(this, "all") ? 0 : 1;
 
-		if (!all && !(format = ast_format_cache_get(this))) {
+		if (!all && !(format = ast_format_cache_get_full(this, "", &format))) {
 			ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this);
 			res = -1;
 			continue;
@@ -385,7 +383,7 @@
 			}
 		}
 
-		ao2_cleanup(format);
+		ao2_s_cleanup(&format);
 	}
 	return res;
 }
@@ -395,7 +393,8 @@
 	return AST_VECTOR_SIZE(&cap->preference_order);
 }
 
-struct ast_format *ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
+struct ast_format *__ast_format_cap_get_format(const struct ast_format_cap *cap, int position,
+	void *debugstorage)
 {
 	struct format_cap_framed *framed;
 
@@ -408,7 +407,7 @@
 	framed = AST_VECTOR_GET(&cap->preference_order, position);
 
 	ast_assert(framed->format != ast_format_none);
-	ao2_ref(framed->format, +1);
+	ao2_ref_full(framed->format, +1, "", debugstorage);
 	return framed->format;
 }
 
diff --git a/main/frame.c b/main/frame.c
index 92b92b6..b6094a7 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -130,7 +130,7 @@
 		    (frames->size < FRAME_CACHE_MAX_SIZE)) {
 			if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
 				(fr->frametype == AST_FRAME_IMAGE)) {
-				ao2_cleanup(fr->subclass.format);
+				ao2_s_cleanup(&fr->subclass.format);
 			}
 
 			AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
@@ -151,7 +151,7 @@
 	if (fr->mallocd & AST_MALLOCD_HDR) {
 		if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
 			(fr->frametype == AST_FRAME_IMAGE)) {
-			ao2_cleanup(fr->subclass.format);
+			ao2_s_cleanup(&fr->subclass.format);
 		}
 
 		ast_free(fr);
@@ -210,7 +210,7 @@
 		out->frametype = fr->frametype;
 		if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) ||
 			(fr->frametype == AST_FRAME_IMAGE)) {
-			out->subclass.format = ao2_bump(fr->subclass.format);
+			ao2_s_set(&out->subclass.format, fr->subclass.format);
 		} else {
 			memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass));
 		}
@@ -323,7 +323,7 @@
 	out->subclass = f->subclass;
 	if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) ||
 		(f->frametype == AST_FRAME_IMAGE)) {
-		ao2_bump(out->subclass.format);
+		ao2_bump_full(out->subclass.format, "", &out->subclass.format);
 	}
 	out->datalen = f->datalen;
 	out->samples = f->samples;
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 11e94c6..244348c 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -2220,7 +2220,7 @@
  */
 static void rtp_engine_mime_type_cleanup(int i)
 {
-	ao2_cleanup(ast_rtp_mime_types[i].payload_type.format);
+	ao2_s_cleanup(&ast_rtp_mime_types[i].payload_type.format);
 	memset(&ast_rtp_mime_types[i], 0, sizeof(struct ast_rtp_mime_type));
 }
 
@@ -2240,7 +2240,7 @@
 	memset(&ast_rtp_mime_types[x], 0, sizeof(struct ast_rtp_mime_type));	
 	if (format) {
 		ast_rtp_mime_types[x].payload_type.asterisk_format = 1;
-		ast_rtp_mime_types[x].payload_type.format = ao2_bump(format);
+		ao2_s_set(&ast_rtp_mime_types[x].payload_type.format, format);
 	} else {
 		ast_rtp_mime_types[x].payload_type.rtp_code = rtp_code;
 	}
diff --git a/main/stasis.c b/main/stasis.c
index 91ad94e..a7bd735 100644
--- a/main/stasis.c
+++ b/main/stasis.c
@@ -345,12 +345,12 @@
 	AST_VECTOR_FREE(&topic->upstream_topics);
 }
 
-struct stasis_topic *stasis_topic_create(const char *name)
+struct stasis_topic *__stasis_topic_create(const char *name, void *debugstorage)
 {
 	struct stasis_topic *topic;
 	int res = 0;
 
-	topic = ao2_t_alloc(sizeof(*topic), topic_dtor, name);
+	topic = ao2_alloc_full(sizeof(*topic), topic_dtor, AO2_ALLOC_OPT_LOCK_MUTEX, name, debugstorage);
 	if (!topic) {
 		return NULL;
 	}
@@ -359,7 +359,7 @@
 	res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX);
 	res |= AST_VECTOR_INIT(&topic->upstream_topics, 0);
 	if (!topic->name || res) {
-		ao2_cleanup(topic);
+		ao2_ref_full(topic, -1, "", debugstorage);
 		return NULL;
 	}
 
@@ -405,7 +405,7 @@
 	 * be bad. */
 	ast_assert(stasis_subscription_is_done(sub));
 
-	ao2_cleanup(sub->topic);
+	ao2_s_cleanup(&sub->topic);
 	sub->topic = NULL;
 	ast_taskprocessor_unreference(sub->mailbox);
 	sub->mailbox = NULL;
@@ -494,8 +494,7 @@
 		ao2_ref(sub, +1);
 	}
 
-	ao2_ref(topic, +1);
-	sub->topic = topic;
+	ao2_s_set(&sub->topic, topic);
 	sub->callback = callback;
 	sub->data = data;
 	ast_cond_init(&sub->join_cond, NULL);
@@ -536,8 +535,8 @@
 {
 	/* The subscription may be the last ref to this topic. Hold
 	 * the topic ref open until after the unlock. */
-	RAII_VAR(struct stasis_topic *, topic,
-		ao2_bump(sub ? sub->topic : NULL), ao2_cleanup);
+	RAII_AO2_S(struct stasis_topic *, topic,
+		ao2_bump_full(sub ? sub->topic : NULL, "", &topic));
 
 	if (!sub) {
 		return NULL;
@@ -824,7 +823,7 @@
 	 * The topic may be unref'ed by the subscription invocation.
 	 * Make sure we hold onto a reference while dispatching.
 	 */
-	ao2_ref(topic, +1);
+	ao2_ref_full(topic, +1, "", &topic);
 	ao2_lock(topic);
 	for (i = 0; i < AST_VECTOR_SIZE(&topic->subscribers); ++i) {
 		struct stasis_subscription *sub = AST_VECTOR_GET(&topic->subscribers, i);
@@ -834,7 +833,7 @@
 		dispatch_message(sub, message, (sub == sync_sub));
 	}
 	ao2_unlock(topic);
-	ao2_ref(topic, -1);
+	ao2_ref_full(topic, -1, "", &topic);
 }
 
 void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
@@ -868,9 +867,9 @@
 {
 	struct stasis_forward *forward = obj;
 
-	ao2_cleanup(forward->from_topic);
+	ao2_s_cleanup(&forward->from_topic);
 	forward->from_topic = NULL;
-	ao2_cleanup(forward->to_topic);
+	ao2_s_cleanup(&forward->to_topic);
 	forward->to_topic = NULL;
 }
 
@@ -925,8 +924,8 @@
 		return ao2_bump(forward);
 	}
 
-	forward->from_topic = ao2_bump(from_topic);
-	forward->to_topic = ao2_bump(to_topic);
+	ao2_s_set(&forward->from_topic, from_topic);
+	ao2_s_set(&forward->to_topic, to_topic);
 
 	topic_lock_both(to_topic, from_topic);
 	res = AST_VECTOR_APPEND(&to_topic->upstream_topics, from_topic);
@@ -950,7 +949,7 @@
 	struct stasis_subscription_change *change = obj;
 
 	ast_string_field_free_memory(change);
-	ao2_cleanup(change->topic);
+	ao2_s_cleanup(&change->topic);
 }
 
 static struct stasis_subscription_change *subscription_change_alloc(struct stasis_topic *topic, const char *uniqueid, const char *description)
@@ -965,8 +964,7 @@
 
 	ast_string_field_set(change, uniqueid, uniqueid);
 	ast_string_field_set(change, description, description);
-	ao2_ref(topic, +1);
-	change->topic = topic;
+	ao2_s_set(&change->topic, topic);
 
 	return change;
 }
@@ -1042,7 +1040,7 @@
 	struct topic_pool_entry *entry = obj;
 
 	entry->forward = stasis_forward_cancel(entry->forward);
-	ao2_cleanup(entry->topic);
+	ao2_s_cleanup(&entry->topic);
 	entry->topic = NULL;
 }
 
@@ -1161,7 +1159,7 @@
 		return NULL;
 	}
 
-	topic_pool_entry->topic = stasis_topic_create(topic_name);
+	topic_pool_entry->topic = __stasis_topic_create(topic_name, &topic_pool_entry->topic);
 	if (!topic_pool_entry->topic) {
 		return NULL;
 	}
@@ -1477,7 +1475,7 @@
 {
 	struct stasis_config *cfg = obj;
 
-	ao2_cleanup(cfg->declined_message_types);
+	ao2_s_cleanup(&cfg->declined_message_types);
 	ast_free(cfg->threadpool_options);
 }
 
@@ -1495,7 +1493,7 @@
 		return NULL;
 	}
 
-	cfg->declined_message_types = ao2_alloc(sizeof(*cfg->declined_message_types),
+	ao2_s_alloc(&cfg->declined_message_types, sizeof(*cfg->declined_message_types),
 		stasis_declined_config_destructor);
 	if (!cfg->declined_message_types) {
 		ao2_ref(cfg, -1);
@@ -1513,7 +1511,7 @@
 
 int stasis_message_type_declined(const char *name)
 {
-	RAII_VAR(struct stasis_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
+	RAII_AO2_S_GLOBAL(struct stasis_config *, cfg, globals);
 	char *name_in_declined;
 	int res;
 
@@ -1521,9 +1519,9 @@
 		return 0;
 	}
 
-	name_in_declined = ao2_find(cfg->declined_message_types->declined, name, OBJ_SEARCH_KEY);
+	name_in_declined = ao2_find_full(cfg->declined_message_types->declined, name, OBJ_SEARCH_KEY, "", &name_in_declined);
 	res = name_in_declined ? 1 : 0;
-	ao2_cleanup(name_in_declined);
+	ao2_s_cleanup(&name_in_declined);
 	if (res) {
 		ast_log(LOG_NOTICE, "Declining to allocate Stasis message type '%s' due to configuration\n", name);
 	}
diff --git a/main/stasis_cache.c b/main/stasis_cache.c
index bd6d6fa..df5fe87 100644
--- a/main/stasis_cache.c
+++ b/main/stasis_cache.c
@@ -73,11 +73,11 @@
 
 	ao2_cleanup(caching_topic->sub);
 	caching_topic->sub = NULL;
-	ao2_cleanup(caching_topic->cache);
+	ao2_s_cleanup(&caching_topic->cache);
 	caching_topic->cache = NULL;
-	ao2_cleanup(caching_topic->topic);
+	ao2_s_cleanup(&caching_topic->topic);
 	caching_topic->topic = NULL;
-	ao2_cleanup(caching_topic->original_topic);
+	ao2_s_cleanup(&caching_topic->original_topic);
 	caching_topic->original_topic = NULL;
 }
 
@@ -868,9 +868,10 @@
 	ao2_cleanup(caching_topic_needs_unref);
 }
 
-struct stasis_caching_topic *stasis_caching_topic_create(struct stasis_topic *original_topic, struct stasis_cache *cache)
+struct stasis_caching_topic *__stasis_caching_topic_create(
+	struct stasis_topic *original_topic, struct stasis_cache *cache, void *debugstorage)
 {
-	RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+	RAII_AO2_S(struct stasis_caching_topic *, caching_topic, NULL);
 	struct stasis_subscription *sub;
 	RAII_VAR(char *, new_name, NULL, ast_free);
 	int ret;
@@ -880,27 +881,25 @@
 		return NULL;
 	}
 
-	caching_topic = ao2_alloc_options(sizeof(*caching_topic),
-		stasis_caching_topic_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
+	caching_topic = ao2_alloc_full(sizeof(*caching_topic),
+		stasis_caching_topic_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK, "", &caching_topic);
 	if (caching_topic == NULL) {
 		return NULL;
 	}
 
-	caching_topic->topic = stasis_topic_create(new_name);
+	caching_topic->topic = __stasis_topic_create(new_name, &caching_topic->topic);
 	if (caching_topic->topic == NULL) {
 		return NULL;
 	}
 
-	ao2_ref(cache, +1);
-	caching_topic->cache = cache;
+	ao2_s_set(&caching_topic->cache, cache);
 
 	sub = internal_stasis_subscribe(original_topic, caching_topic_exec, caching_topic, 0, 0);
 	if (sub == NULL) {
 		return NULL;
 	}
 
-	ao2_ref(original_topic, +1);
-	caching_topic->original_topic = original_topic;
+	ao2_s_set(&caching_topic->original_topic, original_topic);
 
 	/* This is for the reference contained in the subscription above */
 	ao2_ref(caching_topic, +1);
diff --git a/main/stasis_cache_pattern.c b/main/stasis_cache_pattern.c
index 66563c4..df9a62a 100644
--- a/main/stasis_cache_pattern.c
+++ b/main/stasis_cache_pattern.c
@@ -54,9 +54,9 @@
 {
 	struct stasis_cp_all *all = obj;
 
-	ao2_cleanup(all->topic);
+	ao2_s_cleanup(&all->topic);
 	all->topic = NULL;
-	ao2_cleanup(all->topic_cached);
+	ao2_s_cleanup(&all->topic_cached);
 	all->topic_cached = NULL;
 	ao2_cleanup(all->cache);
 	all->cache = NULL;
@@ -68,9 +68,8 @@
 	snapshot_get_id id_fn)
 {
 	RAII_VAR(char *, cached_name, NULL, ast_free);
-	RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup);
+	RAII_AO2_S(struct stasis_cp_all *, all, ao2_s_alloc(&all, sizeof(*all), all_dtor));
 
-	all = ao2_t_alloc(sizeof(*all), all_dtor, name);
 	if (!all) {
 		return NULL;
 	}
@@ -80,8 +79,8 @@
 		return NULL;
 	}
 
-	all->topic = stasis_topic_create(name);
-	all->topic_cached = stasis_topic_create(cached_name);
+	all->topic = __stasis_topic_create(name, &all->topic);
+	all->topic_cached = __stasis_topic_create(cached_name, &all->topic_cached);
 	all->cache = stasis_cache_create(id_fn);
 	all->forward_all_to_cached =
 		stasis_forward_all(all->topic, all->topic_cached);
@@ -91,7 +90,7 @@
 		return NULL;
 	}
 
-	ao2_ref(all, +1);
+	ao2_t_ref(all, +1, name);
 	return all;
 }
 
@@ -129,7 +128,7 @@
 	ast_assert(one->forward_topic_to_all == NULL);
 	ast_assert(one->forward_cached_to_all == NULL);
 
-	ao2_cleanup(one->topic);
+	ao2_s_cleanup(&one->topic);
 	one->topic = NULL;
 }
 
@@ -160,14 +159,13 @@
 struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all,
 	const char *name)
 {
-	RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup);
+	RAII_AO2_S(struct stasis_cp_single *, one, ao2_s_alloc(&one, sizeof(*one), one_dtor));
 
-	one = ao2_t_alloc(sizeof(*one), one_dtor, name);
 	if (!one) {
 		return NULL;
 	}
 
-	one->topic = stasis_topic_create(name);
+	one->topic = __stasis_topic_create(name, &one->topic);
 	if (!one->topic) {
 		return NULL;
 	}
@@ -176,7 +174,7 @@
 		return NULL;
 	}
 
-	ao2_ref(one, +1);
+	ao2_t_ref(one, +1, name);
 	return one;
 }
 
diff --git a/main/stasis_message.c b/main/stasis_message.c
index 37b9a2b..71db77d 100644
--- a/main/stasis_message.c
+++ b/main/stasis_message.c
@@ -103,8 +103,8 @@
 static void stasis_message_dtor(void *obj)
 {
 	struct stasis_message *message = obj;
-	ao2_cleanup(message->type);
-	ao2_cleanup(message->data);
+	ao2_s_cleanup(&message->type);
+	ao2_s_cleanup(&message->data);
 }
 
 struct stasis_message *stasis_message_create_full(struct stasis_message_type *type, void *data, const struct ast_eid *eid)
@@ -121,10 +121,8 @@
 	}
 
 	message->timestamp = ast_tvnow();
-	ao2_ref(type, +1);
-	message->type = type;
-	ao2_ref(data, +1);
-	message->data = data;
+	ao2_s_set(&message->type, type);
+	ao2_s_set(&message->data, data);
 	if (eid) {
 		message->eid_ptr = &message->eid;
 		message->eid = *eid;
diff --git a/main/threadpool.c b/main/threadpool.c
index 9cd33ab..da09d03 100644
--- a/main/threadpool.c
+++ b/main/threadpool.c
@@ -370,7 +370,7 @@
 static void threadpool_destructor(void *obj)
 {
 	struct ast_threadpool *pool = obj;
-	ao2_cleanup(pool->listener);
+	ao2_s_cleanup(&pool->listener);
 }
 
 /*
@@ -913,8 +913,7 @@
 
 	pool->tps = tps;
 	if (listener) {
-		ao2_ref(listener, +1);
-		pool->listener = listener;
+		ao2_s_set(&pool->listener, listener);
 	}
 	ast_threadpool_set_size(pool, pool->options.initial_size);
 	ao2_ref(pool, +1);
@@ -1291,10 +1290,8 @@
 {
 	struct serializer *ser = obj;
 
-	ao2_cleanup(ser->pool);
-	ser->pool = NULL;
-	ao2_cleanup(ser->shutdown_group);
-	ser->shutdown_group = NULL;
+	ao2_s_cleanup(&ser->pool);
+	ao2_s_cleanup(&ser->shutdown_group);
 }
 
 static struct serializer *serializer_create(struct ast_threadpool *pool,
@@ -1306,9 +1303,8 @@
 	if (!ser) {
 		return NULL;
 	}
-	ao2_ref(pool, +1);
-	ser->pool = pool;
-	ser->shutdown_group = ao2_bump(shutdown_group);
+	ao2_s_set(&ser->pool, pool);
+	ao2_s_set(&ser->shutdown_group, shutdown_group);
 	return ser;
 }
 
diff --git a/main/translate.c b/main/translate.c
index 8d37e37..3aa3cbc 100644
--- a/main/translate.c
+++ b/main/translate.c
@@ -297,7 +297,7 @@
 	if (t->destroy) {
 		t->destroy(pvt);
 	}
-	ao2_cleanup(pvt->f.subclass.format);
+	ao2_s_cleanup(&pvt->f.subclass.format);
 	if (pvt->explicit_dst) {
 		ao2_ref(pvt->explicit_dst, -1);
 		pvt->explicit_dst = NULL;
@@ -366,10 +366,10 @@
 	 * C) create one.
 	 */
 	if (!pvt->f.subclass.format) {
-		pvt->f.subclass.format = ao2_bump(pvt->explicit_dst);
+		ao2_s_set(&pvt->f.subclass.format, pvt->explicit_dst);
 
 		if (!pvt->f.subclass.format && !ast_strlen_zero(pvt->t->format)) {
-			pvt->f.subclass.format = ast_format_cache_get(pvt->t->format);
+			pvt->f.subclass.format = ast_format_cache_get_full(pvt->t->format, "", &pvt->f.subclass.format);
 		}
 
 		if (!pvt->f.subclass.format) {
@@ -380,7 +380,7 @@
 				destroy(pvt);
 				return NULL;
 			}
-			pvt->f.subclass.format = ast_format_create(codec);
+			pvt->f.subclass.format = __ast_format_create(codec, &pvt->f.subclass.format);
 			ao2_ref(codec, -1);
 		}
 
@@ -1140,17 +1140,19 @@
 {
 	struct ast_translator *u;
 	char tmp[80];
-	RAII_VAR(struct ast_codec *, src_codec, NULL, ao2_cleanup);
-	RAII_VAR(struct ast_codec *, dst_codec, NULL, ao2_cleanup);
+	RAII_AO2_S(struct ast_codec *, src_codec, NULL);
+	RAII_AO2_S(struct ast_codec *, dst_codec, NULL);
 
-	src_codec = ast_codec_get(t->src_codec.name, t->src_codec.type, t->src_codec.sample_rate);
+	src_codec = __ast_codec_get(
+		t->src_codec.name, t->src_codec.type, t->src_codec.sample_rate, &src_codec);
 	if (!src_codec) {
 		ast_assert(0);
 		ast_log(LOG_WARNING, "Failed to register translator: unknown source codec %s\n", t->src_codec.name);
 		return -1;
 	}
 
-	dst_codec = ast_codec_get(t->dst_codec.name, t->dst_codec.type, t->dst_codec.sample_rate);
+	dst_codec = __ast_codec_get(
+		t->dst_codec.name, t->dst_codec.type, t->dst_codec.sample_rate, &dst_codec);
 	if (!dst_codec) {
 		ast_log(LOG_WARNING, "Failed to register translator: unknown destination codec %s\n", t->dst_codec.name);
 		return -1;

-- 
To view, visit https://gerrit.asterisk.org/3141
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iacb0a51cefaa98c83eab18aa2b7d18850bb33951
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Corey Farrell <git at cfware.com>



More information about the asterisk-code-review mailing list