29 #include "asterisk/_private.h"
58 #define AO2_MAGIC 0xa570b123
75 volatile int total_objects;
76 volatile int total_mem;
77 volatile int total_containers;
78 volatile int total_refs;
79 volatile int total_locked;
82 static struct ao2_stats ao2;
97 c = backtrace(addresses,
N1);
100 for(i = 0; i < c; i++) {
101 ast_verbose(
"%d: %p %s\n", i, addresses[i], strings[i]);
121 p = (
struct astobj2 *) ((
char *) user_data -
sizeof(*p));
128 "bad magic number for object %p. Object is likely destroyed.\n",
148 #define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
158 char *tag,
char *file,
int line,
const char *funcname);
161 int __ao2_lock(
void *user_data,
const char *file,
const char *func,
int line,
const char *
var)
222 int old_refcount = -1;
228 if (ref_log && user_data) {
231 fprintf(ref_log,
"%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
232 user_data, delta,
ast_get_tid(), file, line, funcname, tag);
234 }
else if (old_refcount + delta == 0) {
235 fprintf(ref_log,
"%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
236 user_data, delta,
ast_get_tid(), file, line, funcname, tag);
238 }
else if (delta != 0) {
239 fprintf(ref_log,
"%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ?
"" :
"+"),
240 delta,
ast_get_tid(), file, line, funcname, old_refcount, tag);
268 current_value = ret + delta;
275 if (current_value < 0)
278 if (current_value <= 0) {
291 memset(obj,
'\0',
sizeof(
struct astobj2 *) +
sizeof(
void *) );
307 if (data_size <
sizeof(
void *))
308 data_size =
sizeof(
void *);
310 #if defined(__AST_DEBUG_MALLOC)
311 obj =
__ast_calloc(1,
sizeof(*obj) + data_size, file, line, funcname);
313 obj =
ast_calloc(1,
sizeof(*obj) + data_size);
336 const char *file,
int line,
const char *funcname,
int ref_debug)
341 if ((obj =
internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) {
346 fprintf(ref_log,
"%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj,
ast_get_tid(), file, line, funcname, tag);
356 return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
412 static int hash_zero(
const void *user_obj,
const int flags)
443 const char *funcname,
int ref_debug)
447 const unsigned int num_buckets = hash_fn ? n_buckets : 1;
448 size_t container_size =
sizeof(
struct ao2_container) + num_buckets *
sizeof(
struct bucket);
460 const unsigned int num_buckets = hash_fn ? n_buckets : 1;
461 size_t container_size =
sizeof(
struct ao2_container) + num_buckets *
sizeof(
struct bucket);
555 char *file,
int line,
const char *funcname)
578 static int cb_true(
void *user_data,
void *arg,
int flags)
586 static int cb_true_data(
void *user_data,
void *arg,
void *data,
int flags)
601 char *tag,
char *file,
int line,
const char *funcname)
629 if (!(multi_iterator =
ast_calloc(1,
sizeof(*multi_iterator)))) {
675 for (; i <
last ; i++) {
711 if (ret && (multi_container != NULL)) {
755 if (i == c->
n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
764 if (multi_container != NULL) {
768 return multi_iterator;
777 char *tag,
char *file,
int line,
const char *funcname)
791 char *tag,
char *file,
int line,
const char *funcname)
952 static int cd_cb(
void *obj,
void *arg,
int flag)
960 __ao2_ref_debug(obj, -1,
"deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__);
1005 static int print_cb(
void *obj,
void *arg,
int flag)
1008 char *s = (
char *)obj;
1021 e->
command =
"astobj2 show stats";
1022 e->
usage =
"Usage: astobj2 show stats\n"
1023 " Show astobj2 show stats\n";
1028 ast_cli(a->
fd,
"Objects : %d\n", ao2.total_objects);
1029 ast_cli(a->
fd,
"Containers : %d\n", ao2.total_containers);
1030 ast_cli(a->
fd,
"Memory : %d\n", ao2.total_mem);
1031 ast_cli(a->
fd,
"Locked : %d\n", ao2.total_locked);
1032 ast_cli(a->
fd,
"Refs : %d\n", ao2.total_refs);
1044 static int prof_id = -1;
1050 e->
usage =
"Usage: astobj2 test <num>\n"
1051 " Runs astobj2 test. Creates 'num' objects,\n"
1052 " and test iterators, callbacks and may be other stuff\n";
1066 lim = atoi(a->
argv[2]);
1075 ast_cli(a->
fd,
"container allocated as %p\n", c1);
1082 for (i = 0; i < lim; i++) {
1086 ast_cli(a->
fd,
"object %d allocated as %p\n", i, obj);
1087 sprintf(obj,
"-- this is obj %d --", i);
1098 ast_cli(a->
fd,
"testing iterators, remove every second object\n");
1105 ast_cli(a->
fd,
"iterator on <%s>\n", obj);
1111 ast_cli(a->
fd,
"testing iterators again\n");
1114 ast_cli(a->
fd,
"iterator on <%s>\n", obj);
1119 ast_cli(a->
fd,
"testing callbacks again\n");
1122 ast_verbose(
"now you should see an error message:\n");
1132 AST_CLI_DEFINE(handle_astobj2_stats,
"Print astobj2 statistics"),
1153 char ref_filename[1024];
1158 ref_log = fopen(ref_filename,
"w");
1160 ast_log(
LOG_ERROR,
"Could not open ref debug log file: %s\n", ref_filename);
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
static void * internal_ao2_callback(struct ao2_container *c, const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, char *tag, char *file, int line, const char *funcname)
static struct bucket_entry * internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
void ast_std_free(void *ptr)
int64_t ast_mark(int, int start1_stop0)
#define AST_CLI_DEFINE(fn, txt,...)
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
static int cd_cb(void *obj, void *arg, int flag)
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static int internal_ao2_ref(void *user_data, const int delta)
static void astobj2_cleanup(void)
static void container_destruct(void *c)
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Allocate and initialize an object.
void * __ao2_callback_data(struct ao2_container *c, enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data)
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
static struct ao2_container * internal_ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
descriptor for a cli entry.
void ast_verbose(const char *fmt,...)
void * __ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
#define ao2_t_iterator_next(arg1, arg2)
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var)
Unlock an object.
Continue if a match is not found in the hashed out bucket.
char ** ast_bt_get_symbols(void **addresses, size_t num_frames)
void * __ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg)
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
struct bucket_entry::@222 entry
search_flags
Flags passed to ao2_callback() and ao2_hash_fn() to modify its behaviour.
#define ao2_t_container_alloc(arg1, arg2, arg3, arg4)
Allocate and initialize a container with the desired number of buckets.
void ast_cli(int fd, const char *fmt,...)
static void container_destruct_debug(void *c)
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
void * __ao2_link_debug(struct ao2_container *c, void *new_obj, char *tag, char *file, int line, const char *funcname)
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
static int cd_cb_debug(void *obj, void *arg, int flag)
int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var)
Try locking– (don't block if fail)
void * ao2_object_get_lockaddr(void *obj)
Return the lock address of an object.
void * __ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag, const char *file, int line, const char *funcname, int ref_debug)
Asterisk file paths, configured in asterisk.conf.
int ast_get_tid(void)
Get current thread ID.
struct sla_ringing_trunk * last
int __ao2_ref(void *o, int delta)
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define ao2_ref(o, delta)
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
ao2_destructor_fn destructor_fn
void(* ao2_destructor_fn)(void *)
Typedef for an object destructor. This is called just before freeing the memory for the object...
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static struct astobj2 * INTERNAL_OBJ(void *user_data)
convert from a pointer _p to a user-defined object
#define EXTERNAL_OBJ(_p)
convert from a pointer _p to an astobj2 object
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var)
Lock an object.
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define ao2_t_unlink(arg1, arg2, arg3)
Remove an object from a container.
static void * internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname)
static int cb_true_data(void *user_data, void *arg, void *data, int flags)
similar to cb_true, but is an ao2_callback_data_fn instead
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
const char * ast_config_AST_LOG_DIR
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
struct ao2_container * __ao2_container_alloc(const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
void * __ao2_callback_debug(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname)
static int cb_true(void *user_data, void *arg, int flags)
special callback that matches all
ao2_callback_fn ao2_match_by_addr
a very common callback is one that matches by address.
static int hash_zero(const void *user_obj, const int flags)
always zero hash function
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
struct ao2_container * __ao2_container_alloc_debug(const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname, int ref_debug)
#define ao2_container_alloc(arg1, arg2, arg3)
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
int( ao2_hash_fn)(const void *obj, const int flags)
void * __ao2_unlink(struct ao2_container *c, void *obj)
struct __priv_data priv_data
void * __ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define ast_mutex_init(pmutex)
int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *funcname)
#define ast_mutex_destroy(a)
static void * internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_entry **q)
void * __ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag, char *file, int line, const char *funcname)
void * __ao2_unlink_debug(struct ao2_container *c, void *obj, char *tag, char *file, int line, const char *funcname)
void * __ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn)
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
void * __ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
void * __ao2_link(struct ao2_container *c, void *newobj)
ao2_hash_fn * hash_fn
Event type specific hash function.
void * __ao2_iterator_next(struct ao2_iterator *a)
int( ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags)
Type of a generic callback function.
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
Structure for mutex and tracking information.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.