40 const char *tag,
const char *file,
int line,
const char *func)
50 __ao2_ref(node->
obj, -1, tag ?:
"Remove obj from container", file, line, func);
55 if (flags & AO2_UNLINK_NODE_DEC_COUNT) {
57 #if defined(AO2_DEBUG)
59 int empty = container->nodes - container->
elements;
61 if (container->max_empty_nodes < empty) {
62 container->max_empty_nodes = empty;
64 if (container->
v_table->unlink_stat) {
65 container->
v_table->unlink_stat(container, node);
94 int __ao2_link(
struct ao2_container *
self,
void *obj_new,
int flags,
95 const char *tag,
const char *file,
int line,
const char *func)
101 if (!__is_ao2_object(obj_new, file, line, func)
102 || !__is_ao2_object(
self, file, line, func)) {
106 if (!self->v_table || !self->v_table->new_node || !self->v_table->insert) {
108 __ast_assert_failed(0,
"invalid container v_table", file, line, func);
120 node =
self->v_table->new_node(
self, obj_new, tag, file, line, func);
122 #if defined(AO2_DEBUG)
124 ast_log(LOG_ERROR,
"Container integrity failed before insert.\n");
129 switch (self->v_table->insert(
self, node)) {
133 #if defined(AO2_DEBUG)
134 AO2_DEVMODE_STAT(++self->nodes);
135 if (self->v_table->link_stat) {
136 self->v_table->link_stat(
self, node);
141 #if defined(AO2_DEBUG)
143 ast_log(LOG_ERROR,
"Container integrity failed after insert or replace.\n");
154 if (flags & OBJ_NOLOCK) {
155 __adjust_lock(
self, orig_lock, 0);
175 void *__ao2_unlink(
struct ao2_container *c,
void *user_data,
int flags,
176 const char *tag,
const char *file,
int line,
const char *func)
178 if (!__is_ao2_object(user_data, file, line, func)) {
193 static int cb_true(
void *user_data,
void *arg,
int flags)
201 static int cb_true_data(
void *user_data,
void *arg,
void *data,
int flags)
231 void *cb_fn,
void *arg,
void *data,
enum ao2_callback_type type,
232 const char *tag,
const char *file,
int line,
const char *func)
238 void *traversal_state;
244 if (!__is_ao2_object(
self, file, line, func)) {
249 || !self->v_table->traverse_first || !self->v_table->traverse_next) {
251 __ast_assert_failed(0,
"invalid container v_table", file, line, func);
269 NULL,
"OBJ_MULTIPLE return container creation");
270 if (!multi_container) {
273 if (!(multi_iterator =
ast_calloc(1,
sizeof(*multi_iterator)))) {
274 ao2_t_ref(multi_container, -1,
"OBJ_MULTIPLE interator creation failed.");
281 if (type == AO2_CALLBACK_WITH_DATA) {
291 if (type == AO2_CALLBACK_WITH_DATA) {
299 if (flags & OBJ_NOLOCK) {
318 for (node = self->v_table->traverse_first(
self, flags, arg, traversal_state);
320 node =
self->v_table->traverse_next(
self, traversal_state, node)) {
325 if (type == AO2_CALLBACK_WITH_DATA) {
326 match &= cb_withdata(node->
obj, arg, data, flags);
328 match &= cb_default(node->
obj, arg, flags);
351 if (multi_container) {
356 __ao2_link(multi_container, node->
obj, flags, tag, file, line, func);
365 __ao2_ref(ret, 1, tag ?:
"Traversal found object", file, line, func);
372 if (multi_container || (flags & OBJ_NODATA)) {
375 __container_unlink_node_debug(node, ulflag, tag, file, line, func);
384 if (self->v_table->traverse_cleanup) {
385 self->v_table->traverse_cleanup(traversal_state);
392 if (flags & OBJ_NOLOCK) {
393 __adjust_lock(
self, orig_lock, 0);
399 if (multi_container) {
402 ao2_t_ref(multi_container, -1,
403 "OBJ_MULTIPLE for multiple objects traversal complete.");
404 return multi_iterator;
411 ao2_callback_fn *cb_fn,
void *arg,
const char *tag,
const char *file,
int line,
414 return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, file, line, func);
419 int line,
const char *func)
421 return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, file, line, func);
428 const char *tag,
const char *file,
int line,
const char *func)
430 void *arged = (
void *) arg;
437 return __ao2_callback(c, flags, c->
cmp_fn, arged, tag, file, line, func);
441 const char *tag,
const char *file,
int line,
const char *func)
451 if (flags & OBJ_NOLOCK) {
458 while ((proxy = ao2_find(c, arg, flags | OBJ_NOLOCK))) {
459 obj = __ao2_weakproxy_get_object(proxy, 0, tag ?: __PRETTY_FUNCTION__, file, line, func);
472 if (flags & OBJ_NOLOCK) {
474 __adjust_lock(c, orig_lock, 1);
492 ao2_t_ref(c, +1,
"Init iterator with container.");
499 if (!is_ao2_object(iter->
c)) {
524 __adjust_lock(iter->
c, orig_lock, 0);
540 ao2_t_ref(iter->
c, -1,
"Unref iterator in ao2_iterator_destroy");
557 const char *tag,
const char *file,
int line,
const char *func)
563 if (!__is_ao2_object(iter->
c, file, line, func)) {
569 __ast_assert_failed(0,
"invalid iterator container v_table", file, line, func);
599 __container_unlink_node_debug(node, AO2_UNLINK_NODE_DEC_COUNT, tag, file, line, func);
604 __ao2_ref(ret, +1, tag ?:
"Next iterator object.", file, line, func);
622 __adjust_lock(iter->
c, orig_lock, 0);
635 void container_destruct(
void *_c)
641 ao2_t_callback(c, OBJ_UNLINK | OBJ_NODATA |
OBJ_MULTIPLE, NULL, NULL,
642 "container_destruct called");
649 #if defined(AO2_DEBUG)
666 static int dup_obj_cb(
void *obj,
void *arg,
int flags)
678 if (!(flags & OBJ_NOLOCK)) {
685 ao2_t_ref(obj, -1,
"Failed to put this object into the dest container.");
692 if (!(flags & OBJ_NOLOCK)) {
731 if (!(flags & OBJ_NOLOCK)) {
738 ao2_t_ref(obj, -1,
"Failed to put this object into the dest container.");
745 if (!(flags & OBJ_NOLOCK)) {
759 if (!__is_ao2_object(orig, file, line, func)) {
765 __ast_assert_failed(0,
"invalid container v_table", file, line, func);
777 if (flags & OBJ_NOLOCK) {
781 if (flags & OBJ_NOLOCK) {
786 __ao2_ref(clone, -1, tag ?:
"Clone creation failed", file, line, func);
794 if (!is_ao2_object(
self) || !self->v_table) {
795 prnt(where,
"Invalid container\n");
800 if (!(flags & OBJ_NOLOCK)) {
804 prnt(where,
"Container name: %s\n", name);
806 #if defined(AO2_DEBUG)
807 if (self->v_table->dump) {
808 self->v_table->dump(
self, where, prnt, prnt_obj);
812 prnt(where,
"Container dump not available.\n");
814 if (!(flags & OBJ_NOLOCK)) {
821 if (!is_ao2_object(
self) || !self->v_table) {
822 prnt(where,
"Invalid container\n");
827 if (!(flags & OBJ_NOLOCK)) {
831 prnt(where,
"Container name: %s\n", name);
833 prnt(where,
"Number of objects: %d\n", self->elements);
834 #if defined(AO2_DEBUG)
835 prnt(where,
"Number of nodes: %d\n", self->nodes);
836 prnt(where,
"Number of empty nodes: %d\n", self->nodes - self->elements);
846 prnt(where,
"Maximum empty nodes: %d\n", self->max_empty_nodes);
847 if (self->v_table->stats) {
848 self->v_table->stats(
self, where, prnt);
851 if (!(flags & OBJ_NOLOCK)) {
860 if (!is_ao2_object(
self) || !self->v_table) {
865 #if defined(AO2_DEBUG)
866 if (!self->v_table->integrity) {
871 if (!(flags & OBJ_NOLOCK)) {
874 res =
self->v_table->integrity(
self);
875 if (!(flags & OBJ_NOLOCK)) {
882 #if defined(AO2_DEBUG)
885 struct ao2_reg_container {
894 struct ao2_reg_partial_key {
901 struct ao2_reg_match {
909 #if defined(AO2_DEBUG)
910 static int ao2_reg_sort_cb(
const void *obj_left,
const void *obj_right,
int flags)
912 const struct ao2_reg_container *reg_left = obj_left;
918 const struct ao2_reg_container *reg_right = obj_right;
920 cmp = strcasecmp(reg_left->name, reg_right->name);
925 const char *name = obj_right;
927 cmp = strcasecmp(reg_left->name, name);
932 const struct ao2_reg_partial_key *partial_key = obj_right;
934 cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
947 #if defined(AO2_DEBUG)
948 static void ao2_reg_destructor(
void *v_doomed)
950 struct ao2_reg_container *doomed = v_doomed;
952 if (doomed->registered) {
953 ao2_t_ref(doomed->registered, -1,
"Releasing registered container.");
961 #if defined(AO2_DEBUG)
962 struct ao2_reg_container *reg;
971 ao2_t_ref(
self, +1,
"Registering container.");
972 reg->registered =
self;
973 reg->prnt_obj = prnt_obj;
974 strcpy(reg->name, name);
976 if (!ao2_t_link(reg_containers, reg,
"Save registration object.")) {
980 ao2_t_ref(reg, -1,
"Done registering container.");
987 #if defined(AO2_DEBUG)
989 "Unregister container");
993 #if defined(AO2_DEBUG)
994 static int ao2_complete_reg_cb(
void *obj,
void *arg,
int flags)
996 struct ao2_reg_container *reg = obj;
1006 #if defined(AO2_DEBUG)
1007 static char *complete_container_names(
struct ast_cli_args *a)
1009 struct ao2_reg_partial_key partial_key;
1015 partial_key.len = strlen(a->word);
1016 partial_key.name = a->word;
1018 ao2_complete_reg_cb, &partial_key);
1024 #if defined(AO2_DEBUG)
1034 static void cli_output(
void *where,
const char *fmt, ...) __attribute__((format(printf, 2, 3)));
1035 static
void cli_output(
void *where, const
char *fmt, ...)
1056 #if defined(AO2_DEBUG)
1061 struct ao2_reg_container *reg;
1065 e->
command =
"astobj2 container dump";
1067 "Usage: astobj2 container dump <name>\n"
1068 " Show contents of the container <name>.\n";
1071 return complete_container_names(a);
1075 return CLI_SHOWUSAGE;
1083 ao2_t_ref(reg, -1,
"Done with registered container object.");
1085 ast_cli(a->fd,
"Container '%s' not found.\n", name);
1092 #if defined(AO2_DEBUG)
1097 struct ao2_reg_container *reg;
1101 e->
command =
"astobj2 container stats";
1103 "Usage: astobj2 container stats <name>\n"
1104 " Show statistics about the specified container <name>.\n";
1107 return complete_container_names(a);
1111 return CLI_SHOWUSAGE;
1118 ao2_t_ref(reg, -1,
"Done with registered container object.");
1120 ast_cli(a->fd,
"Container '%s' not found.\n", name);
1127 #if defined(AO2_DEBUG)
1132 struct ao2_reg_container *reg;
1136 e->
command =
"astobj2 container check";
1138 "Usage: astobj2 container check <name>\n"
1139 " Perform a container integrity check on <name>.\n";
1142 return complete_container_names(a);
1146 return CLI_SHOWUSAGE;
1152 ast_cli(a->fd,
"Container check of '%s': %s.\n", name,
1154 ao2_t_ref(reg, -1,
"Done with registered container object.");
1156 ast_cli(a->fd,
"Container '%s' not found.\n", name);
1163 #if defined(AO2_DEBUG)
1165 AST_CLI_DEFINE(handle_cli_astobj2_container_dump,
"Show container contents"),
1166 AST_CLI_DEFINE(handle_cli_astobj2_container_stats,
"Show container statistics"),
1167 AST_CLI_DEFINE(handle_cli_astobj2_container_check,
"Perform a container integrity check"),
1171 #if defined(AO2_DEBUG)
1172 static void container_cleanup(
void)
1174 ao2_t_ref(reg_containers, -1,
"Releasing container registration container");
1175 reg_containers = NULL;
1181 int container_init(
void)
1183 #if defined(AO2_DEBUG)
1186 "Container registration container.");
1187 if (!reg_containers) {
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ao2_iterator_count(struct ao2_iterator *iter)
Get a count of the iterated container objects.
void( ao2_prnt_fn)(void *where, const char *fmt,...)
Print output.
void( ao2_prnt_obj_fn)(void *v_obj, void *where, ao2_prnt_fn *prnt)
Print object key.
Asterisk main include file. File version handling, generic pbx functions.
ao2_container_destroy_fn destroy
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
ao2_lock_req
Which lock to request.
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
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
The arg parameter is a search key, but is not an object.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Common, private definitions for astobj2.
descriptor for a cli entry.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ao2_iterator_restart(struct ao2_iterator *iter)
Restart an iteration.
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Assume that the ao2_container is already locked.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
#define ast_strdup(str)
A wrapper for strdup()
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
search_flags
Flags passed to ao2_callback_fn(), ao2_hash_fn(), and ao2_sort_fn() to modify behaviour.
static int cb_true(void *user_data, void *arg, int flags)
special callback that matches all
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
int ao2_match_by_addr(void *user_data, void *arg, int flags)
another convenience function is a callback that matches on address
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
#define ao2_weakproxy_get_object(weakproxy, flags)
Get the object associated with weakproxy.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
const struct ao2_container_methods * v_table
struct ao2_container * container
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
Display contents of the specified container.
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Support for dynamic strings.
ao2_iterator_next_fn iterator_next
int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy object references associated with src container weakproxies into the dest container.
#define ast_calloc(num, len)
A wrapper for calloc()
unsigned int destroying
TRUE if the container is being destroyed.
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
static int dup_weakproxy_cb(void *proxy, void *arg, int flags)
Copy obj associated with a weakproxy into the arg container.
Prototypes for public functions only of internal interest,.
#define AO2_TRAVERSAL_STATE_SIZE
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
Display statistics of the specified container.
Assume that the ao2_container is already locked.
The arg parameter is an object of the same type.
Replace objects with duplicate keys in container.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
Common, private definitions for astobj2 containers.
#define ao2_t_find(container, arg, flags, tag)
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Search option field mask.
struct ao2_container * my_container
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
ao2_container_alloc_empty_clone_fn alloc_empty_clone
Create an empty copy of this container.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
int( ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags)
Type of a generic callback 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)