Astobj2: Ensure all calls to __adjust_lock pass a valid object.
[asterisk/asterisk.git] / main / astobj2_hash.c
1 /*
2  * astobj2_hash - Hash table implementation for astobj2.
3  *
4  * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Hash table functions implementing astobj2 containers.
20  *
21  * \author Richard Mudgett <rmudgett@digium.com>
22  */
23
24 #include "asterisk.h"
25
26 ASTERISK_REGISTER_FILE()
27
28 #include "asterisk/_private.h"
29 #include "asterisk/astobj2.h"
30 #include "astobj2_private.h"
31 #include "astobj2_container_private.h"
32 #include "asterisk/dlinkedlists.h"
33 #include "asterisk/utils.h"
34
35 /*!
36  * A structure to create a linked list of entries,
37  * used within a bucket.
38  */
39 struct hash_bucket_node {
40         /*!
41          * \brief Items common to all container nodes.
42          * \note Must be first in the specific node struct.
43          */
44         struct ao2_container_node common;
45         /*! Next node links in the list. */
46         AST_DLLIST_ENTRY(hash_bucket_node) links;
47         /*! Hash bucket holding the node. */
48         int my_bucket;
49 };
50
51 struct hash_bucket {
52         /*! List of objects held in the bucket. */
53         AST_DLLIST_HEAD_NOLOCK(, hash_bucket_node) list;
54 #if defined(AO2_DEBUG)
55         /*! Number of elements currently in the bucket. */
56         int elements;
57         /*! Maximum number of elements in the bucket. */
58         int max_elements;
59 #endif  /* defined(AO2_DEBUG) */
60 };
61
62 /*!
63  * A hash container in addition to values common to all
64  * container types, stores the hash callback function, the
65  * number of hash buckets, and the hash bucket heads.
66  */
67 struct ao2_container_hash {
68         /*!
69          * \brief Items common to all containers.
70          * \note Must be first in the specific container struct.
71          */
72         struct ao2_container common;
73         ao2_hash_fn *hash_fn;
74         /*! Number of hash buckets in this container. */
75         int n_buckets;
76         /*! Hash bucket array of n_buckets.  Variable size. */
77         struct hash_bucket buckets[0];
78 };
79
80 /*! Traversal state to restart a hash container traversal. */
81 struct hash_traversal_state {
82         /*! Active sort function in the traversal if not NULL. */
83         ao2_sort_fn *sort_fn;
84         /*! Saved comparison callback arg pointer. */
85         void *arg;
86         /*! Starting hash bucket */
87         int bucket_start;
88         /*! Stopping hash bucket */
89         int bucket_last;
90         /*! Saved search flags to control traversing the container. */
91         enum search_flags flags;
92         /*! TRUE if it is a descending search */
93         unsigned int descending:1;
94 };
95
96 struct hash_traversal_state_check {
97         /*
98          * If we have a division by zero compile error here then there
99          * is not enough room for the state.  Increase AO2_TRAVERSAL_STATE_SIZE.
100          */
101         char check[1 / (AO2_TRAVERSAL_STATE_SIZE / sizeof(struct hash_traversal_state))];
102 };
103
104 /*!
105  * \internal
106  * \brief Create an empty copy of this container.
107  * \since 12.0.0
108  *
109  * \param self Container to operate upon.
110  *
111  * \retval empty-clone-container on success.
112  * \retval NULL on error.
113  */
114 static struct ao2_container *hash_ao2_alloc_empty_clone(struct ao2_container_hash *self)
115 {
116         if (!is_ao2_object(self)) {
117                 return NULL;
118         }
119
120         return ao2_t_container_alloc_hash(ao2_options_get(self), self->common.options, self->n_buckets,
121                 self->hash_fn, self->common.sort_fn, self->common.cmp_fn, "Clone hash container");
122 }
123
124 /*!
125  * \internal
126  * \brief Create an empty copy of this container. (Debug version)
127  * \since 12.0.0
128  *
129  * \param self Container to operate upon.
130  * \param tag used for debugging.
131  * \param file Debug file name invoked from
132  * \param line Debug line invoked from
133  * \param func Debug function name invoked from
134  * \param ref_debug TRUE if to output a debug reference message.
135  *
136  * \retval empty-clone-container on success.
137  * \retval NULL on error.
138  */
139 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)
140 {
141         if (!is_ao2_object(self)) {
142                 return NULL;
143         }
144
145         return __ao2_container_alloc_hash_debug(ao2_options_get(self), self->common.options,
146                 self->n_buckets, self->hash_fn, self->common.sort_fn, self->common.cmp_fn,
147                 tag, file, line, func, ref_debug);
148 }
149
150 /*!
151  * \internal
152  * \brief Destroy a hash container list node.
153  * \since 12.0.0
154  *
155  * \param v_doomed Container node to destroy.
156  *
157  * \details
158  * The container node unlinks itself from the container as part
159  * of its destruction.  The node must be destroyed while the
160  * container is already locked.
161  *
162  * \note The container must be locked when the node is
163  * unreferenced.
164  *
165  * \return Nothing
166  */
167 static void hash_ao2_node_destructor(void *v_doomed)
168 {
169         struct hash_bucket_node *doomed = v_doomed;
170
171         if (doomed->common.is_linked) {
172                 struct ao2_container_hash *my_container;
173                 struct hash_bucket *bucket;
174
175                 /*
176                  * Promote to write lock if not already there.  Since
177                  * adjust_lock() can potentially release and block waiting for a
178                  * write lock, care must be taken to ensure that node references
179                  * are released before releasing the container references.
180                  *
181                  * Node references held by an iterator can only be held while
182                  * the iterator also holds a reference to the container.  These
183                  * node references must be unreferenced before the container can
184                  * be unreferenced to ensure that the node will not get a
185                  * negative reference and the destructor called twice for the
186                  * same node.
187                  */
188                 my_container = (struct ao2_container_hash *) doomed->common.my_container;
189                 ast_assert(is_ao2_object(my_container));
190
191                 __adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
192
193 #if defined(AO2_DEBUG)
194                 if (!my_container->common.destroying
195                         && ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
196                         ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
197                 }
198 #endif  /* defined(AO2_DEBUG) */
199                 bucket = &my_container->buckets[doomed->my_bucket];
200                 AST_DLLIST_REMOVE(&bucket->list, doomed, links);
201                 AO2_DEVMODE_STAT(--my_container->common.nodes);
202         }
203
204         /*
205          * We could have an object in the node if the container is being
206          * destroyed or the node had not been linked in yet.
207          */
208         if (doomed->common.obj) {
209                 __container_unlink_node(&doomed->common, AO2_UNLINK_NODE_UNLINK_OBJECT);
210         }
211 }
212
213 /*!
214  * \internal
215  * \brief Create a new container node.
216  * \since 12.0.0
217  *
218  * \param self Container to operate upon.
219  * \param obj_new Object to put into the node.
220  * \param tag used for debugging.
221  * \param file Debug file name invoked from
222  * \param line Debug line invoked from
223  * \param func Debug function name invoked from
224  *
225  * \retval initialized-node on success.
226  * \retval NULL on error.
227  */
228 static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *self, void *obj_new, const char *tag, const char *file, int line, const char *func)
229 {
230         struct hash_bucket_node *node;
231         int i;
232
233         node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
234         if (!node) {
235                 return NULL;
236         }
237
238         i = abs(self->hash_fn(obj_new, OBJ_SEARCH_OBJECT));
239         i %= self->n_buckets;
240
241         if (tag) {
242                 __ao2_ref_debug(obj_new, +1, tag, file, line, func);
243         } else {
244                 ao2_t_ref(obj_new, +1, "Container node creation");
245         }
246         node->common.obj = obj_new;
247         node->common.my_container = (struct ao2_container *) self;
248         node->my_bucket = i;
249
250         return node;
251 }
252
253 /*!
254  * \internal
255  * \brief Insert a node into this container.
256  * \since 12.0.0
257  *
258  * \param self Container to operate upon.
259  * \param node Container node to insert into the container.
260  *
261  * \return enum ao2_container_insert value.
262  */
263 static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash *self,
264         struct hash_bucket_node *node)
265 {
266         int cmp;
267         struct hash_bucket *bucket;
268         struct hash_bucket_node *cur;
269         ao2_sort_fn *sort_fn;
270         uint32_t options;
271
272         bucket = &self->buckets[node->my_bucket];
273         sort_fn = self->common.sort_fn;
274         options = self->common.options;
275
276         if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
277                 if (sort_fn) {
278                         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
279                                 cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
280                                 if (cmp > 0) {
281                                         continue;
282                                 }
283                                 if (cmp < 0) {
284                                         AST_DLLIST_INSERT_AFTER_CURRENT(node, links);
285                                         return AO2_CONTAINER_INSERT_NODE_INSERTED;
286                                 }
287                                 switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
288                                 default:
289                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
290                                         break;
291                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
292                                         /* Reject all objects with the same key. */
293                                         return AO2_CONTAINER_INSERT_NODE_REJECTED;
294                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
295                                         if (cur->common.obj == node->common.obj) {
296                                                 /* Reject inserting the same object */
297                                                 return AO2_CONTAINER_INSERT_NODE_REJECTED;
298                                         }
299                                         break;
300                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
301                                         SWAP(cur->common.obj, node->common.obj);
302                                         ao2_t_ref(node, -1, "Discard the new node.");
303                                         return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
304                                 }
305                         }
306                         AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
307                 }
308                 AST_DLLIST_INSERT_HEAD(&bucket->list, node, links);
309         } else {
310                 if (sort_fn) {
311                         AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
312                                 cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
313                                 if (cmp < 0) {
314                                         continue;
315                                 }
316                                 if (cmp > 0) {
317                                         AST_DLLIST_INSERT_BEFORE_CURRENT(node, links);
318                                         return AO2_CONTAINER_INSERT_NODE_INSERTED;
319                                 }
320                                 switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
321                                 default:
322                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
323                                         break;
324                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
325                                         /* Reject all objects with the same key. */
326                                         return AO2_CONTAINER_INSERT_NODE_REJECTED;
327                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
328                                         if (cur->common.obj == node->common.obj) {
329                                                 /* Reject inserting the same object */
330                                                 return AO2_CONTAINER_INSERT_NODE_REJECTED;
331                                         }
332                                         break;
333                                 case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
334                                         SWAP(cur->common.obj, node->common.obj);
335                                         ao2_t_ref(node, -1, "Discard the new node.");
336                                         return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
337                                 }
338                         }
339                         AST_DLLIST_TRAVERSE_SAFE_END;
340                 }
341                 AST_DLLIST_INSERT_TAIL(&bucket->list, node, links);
342         }
343         return AO2_CONTAINER_INSERT_NODE_INSERTED;
344 }
345
346 /*!
347  * \internal
348  * \brief Find the first hash container node in a traversal.
349  * \since 12.0.0
350  *
351  * \param self Container to operate upon.
352  * \param flags search_flags to control traversing the container
353  * \param arg Comparison callback arg parameter.
354  * \param state Traversal state to restart hash container traversal.
355  *
356  * \retval node-ptr of found node (Reffed).
357  * \retval NULL when no node found.
358  */
359 static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *self, enum search_flags flags, void *arg, struct hash_traversal_state *state)
360 {
361         struct hash_bucket_node *node;
362         int bucket_cur;
363         int cmp;
364
365         memset(state, 0, sizeof(*state));
366         state->arg = arg;
367         state->flags = flags;
368
369         /* Determine traversal order. */
370         switch (flags & OBJ_ORDER_MASK) {
371         case OBJ_ORDER_POST:
372         case OBJ_ORDER_DESCENDING:
373                 state->descending = 1;
374                 break;
375         case OBJ_ORDER_PRE:
376         case OBJ_ORDER_ASCENDING:
377         default:
378                 break;
379         }
380
381         /*
382          * If lookup by pointer or search key, run the hash and optional
383          * sort functions.  Otherwise, traverse the whole container.
384          */
385         switch (flags & OBJ_SEARCH_MASK) {
386         case OBJ_SEARCH_OBJECT:
387         case OBJ_SEARCH_KEY:
388                 /* we know hash can handle this case */
389                 bucket_cur = abs(self->hash_fn(arg, flags & OBJ_SEARCH_MASK));
390                 bucket_cur %= self->n_buckets;
391                 state->sort_fn = self->common.sort_fn;
392                 break;
393         case OBJ_SEARCH_PARTIAL_KEY:
394                 /* scan all buckets for partial key matches */
395                 bucket_cur = -1;
396                 state->sort_fn = self->common.sort_fn;
397                 break;
398         default:
399                 /* don't know, let's scan all buckets */
400                 bucket_cur = -1;
401                 state->sort_fn = NULL;
402                 break;
403         }
404
405         if (state->descending) {
406                 /*
407                  * Determine the search boundaries of a descending traversal.
408                  *
409                  * bucket_cur downto state->bucket_last
410                  */
411                 if (bucket_cur < 0) {
412                         bucket_cur = self->n_buckets - 1;
413                         state->bucket_last = 0;
414                 } else {
415                         state->bucket_last = bucket_cur;
416                 }
417                 state->bucket_start = bucket_cur;
418
419                 /* For each bucket */
420                 for (; state->bucket_last <= bucket_cur; --bucket_cur) {
421                         /* For each node in the bucket. */
422                         for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
423                                 node;
424                                 node = AST_DLLIST_PREV(node, links)) {
425                                 if (!node->common.obj) {
426                                         /* Node is empty */
427                                         continue;
428                                 }
429
430                                 if (state->sort_fn) {
431                                         /* Filter node through the sort_fn */
432                                         cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
433                                         if (cmp > 0) {
434                                                 continue;
435                                         }
436                                         if (cmp < 0) {
437                                                 /* No more nodes in this bucket are possible to match. */
438                                                 break;
439                                         }
440                                 }
441
442                                 /* We have the first traversal node */
443                                 __ao2_ref(node, +1);
444                                 return node;
445                         }
446                 }
447         } else {
448                 /*
449                  * Determine the search boundaries of an ascending traversal.
450                  *
451                  * bucket_cur to state->bucket_last-1
452                  */
453                 if (bucket_cur < 0) {
454                         bucket_cur = 0;
455                         state->bucket_last = self->n_buckets;
456                 } else {
457                         state->bucket_last = bucket_cur + 1;
458                 }
459                 state->bucket_start = bucket_cur;
460
461                 /* For each bucket */
462                 for (; bucket_cur < state->bucket_last; ++bucket_cur) {
463                         /* For each node in the bucket. */
464                         for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
465                                 node;
466                                 node = AST_DLLIST_NEXT(node, links)) {
467                                 if (!node->common.obj) {
468                                         /* Node is empty */
469                                         continue;
470                                 }
471
472                                 if (state->sort_fn) {
473                                         /* Filter node through the sort_fn */
474                                         cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
475                                         if (cmp < 0) {
476                                                 continue;
477                                         }
478                                         if (cmp > 0) {
479                                                 /* No more nodes in this bucket are possible to match. */
480                                                 break;
481                                         }
482                                 }
483
484                                 /* We have the first traversal node */
485                                 __ao2_ref(node, +1);
486                                 return node;
487                         }
488                 }
489         }
490
491         return NULL;
492 }
493
494 /*!
495  * \internal
496  * \brief Find the next hash container node in a traversal.
497  * \since 12.0.0
498  *
499  * \param self Container to operate upon.
500  * \param state Traversal state to restart hash container traversal.
501  * \param prev Previous node returned by the traversal search functions.
502  *    The ref ownership is passed back to this function.
503  *
504  * \retval node-ptr of found node (Reffed).
505  * \retval NULL when no node found.
506  */
507 static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *self, struct hash_traversal_state *state, struct hash_bucket_node *prev)
508 {
509         struct hash_bucket_node *node;
510         void *arg;
511         enum search_flags flags;
512         int bucket_cur;
513         int cmp;
514
515         arg = state->arg;
516         flags = state->flags;
517         bucket_cur = prev->my_bucket;
518         node = prev;
519
520         /*
521          * This function is structured the same as hash_ao2_find_first()
522          * intentionally.  We are resuming the search loops from
523          * hash_ao2_find_first() in order to find the next node.  The
524          * search loops must be resumed where hash_ao2_find_first()
525          * returned with the first node.
526          */
527         if (state->descending) {
528                 goto hash_descending_resume;
529
530                 /* For each bucket */
531                 for (; state->bucket_last <= bucket_cur; --bucket_cur) {
532                         /* For each node in the bucket. */
533                         for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
534                                 node;
535                                 node = AST_DLLIST_PREV(node, links)) {
536                                 if (!node->common.obj) {
537                                         /* Node is empty */
538                                         continue;
539                                 }
540
541                                 if (state->sort_fn) {
542                                         /* Filter node through the sort_fn */
543                                         cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
544                                         if (cmp > 0) {
545                                                 continue;
546                                         }
547                                         if (cmp < 0) {
548                                                 /* No more nodes in this bucket are possible to match. */
549                                                 break;
550                                         }
551                                 }
552
553                                 /* We have the next traversal node */
554                                 __ao2_ref(node, +1);
555
556                                 /*
557                                  * Dereferencing the prev node may result in our next node
558                                  * object being removed by another thread.  This could happen if
559                                  * the container uses RW locks and the container was read
560                                  * locked.
561                                  */
562                                 __ao2_ref(prev, -1);
563                                 if (node->common.obj) {
564                                         return node;
565                                 }
566                                 prev = node;
567
568 hash_descending_resume:;
569                         }
570                 }
571         } else {
572                 goto hash_ascending_resume;
573
574                 /* For each bucket */
575                 for (; bucket_cur < state->bucket_last; ++bucket_cur) {
576                         /* For each node in the bucket. */
577                         for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
578                                 node;
579                                 node = AST_DLLIST_NEXT(node, links)) {
580                                 if (!node->common.obj) {
581                                         /* Node is empty */
582                                         continue;
583                                 }
584
585                                 if (state->sort_fn) {
586                                         /* Filter node through the sort_fn */
587                                         cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
588                                         if (cmp < 0) {
589                                                 continue;
590                                         }
591                                         if (cmp > 0) {
592                                                 /* No more nodes in this bucket are possible to match. */
593                                                 break;
594                                         }
595                                 }
596
597                                 /* We have the next traversal node */
598                                 __ao2_ref(node, +1);
599
600                                 /*
601                                  * Dereferencing the prev node may result in our next node
602                                  * object being removed by another thread.  This could happen if
603                                  * the container uses RW locks and the container was read
604                                  * locked.
605                                  */
606                                 __ao2_ref(prev, -1);
607                                 if (node->common.obj) {
608                                         return node;
609                                 }
610                                 prev = node;
611
612 hash_ascending_resume:;
613                         }
614                 }
615         }
616
617         /* No more nodes in the container left to traverse. */
618         __ao2_ref(prev, -1);
619         return NULL;
620 }
621
622 /*!
623  * \internal
624  * \brief Find the next non-empty iteration node in the container.
625  * \since 12.0.0
626  *
627  * \param self Container to operate upon.
628  * \param node Previous node returned by the iterator.
629  * \param flags search_flags to control iterating the container.
630  *   Only AO2_ITERATOR_DESCENDING is useful by the method.
631  *
632  * \note The container is already locked.
633  *
634  * \retval node on success.
635  * \retval NULL on error or no more nodes in the container.
636  */
637 static struct hash_bucket_node *hash_ao2_iterator_next(struct ao2_container_hash *self, struct hash_bucket_node *node, enum ao2_iterator_flags flags)
638 {
639         int cur_bucket;
640
641         if (flags & AO2_ITERATOR_DESCENDING) {
642                 if (node) {
643                         cur_bucket = node->my_bucket;
644
645                         /* Find next non-empty node. */
646                         for (;;) {
647                                 node = AST_DLLIST_PREV(node, links);
648                                 if (!node) {
649                                         break;
650                                 }
651                                 if (node->common.obj) {
652                                         /* Found a non-empty node. */
653                                         return node;
654                                 }
655                         }
656                 } else {
657                         /* Find first non-empty node. */
658                         cur_bucket = self->n_buckets;
659                 }
660
661                 /* Find a non-empty node in the remaining buckets */
662                 while (0 <= --cur_bucket) {
663                         node = AST_DLLIST_LAST(&self->buckets[cur_bucket].list);
664                         while (node) {
665                                 if (node->common.obj) {
666                                         /* Found a non-empty node. */
667                                         return node;
668                                 }
669                                 node = AST_DLLIST_PREV(node, links);
670                         }
671                 }
672         } else {
673                 if (node) {
674                         cur_bucket = node->my_bucket;
675
676                         /* Find next non-empty node. */
677                         for (;;) {
678                                 node = AST_DLLIST_NEXT(node, links);
679                                 if (!node) {
680                                         break;
681                                 }
682                                 if (node->common.obj) {
683                                         /* Found a non-empty node. */
684                                         return node;
685                                 }
686                         }
687                 } else {
688                         /* Find first non-empty node. */
689                         cur_bucket = -1;
690                 }
691
692                 /* Find a non-empty node in the remaining buckets */
693                 while (++cur_bucket < self->n_buckets) {
694                         node = AST_DLLIST_FIRST(&self->buckets[cur_bucket].list);
695                         while (node) {
696                                 if (node->common.obj) {
697                                         /* Found a non-empty node. */
698                                         return node;
699                                 }
700                                 node = AST_DLLIST_NEXT(node, links);
701                         }
702                 }
703         }
704
705         /* No more nodes to visit in the container. */
706         return NULL;
707 }
708
709 #if defined(AO2_DEBUG)
710 /*!
711  * \internal
712  * \brief Increment the hash container linked object statistic.
713  * \since 12.0.0
714  *
715  * \param hash Container to operate upon.
716  * \param hash_node Container node linking object to.
717  *
718  * \return Nothing
719  */
720 static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
721 {
722         struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
723         struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
724         int i = node->my_bucket;
725
726         ++self->buckets[i].elements;
727         if (self->buckets[i].max_elements < self->buckets[i].elements) {
728                 self->buckets[i].max_elements = self->buckets[i].elements;
729         }
730 }
731 #endif  /* defined(AO2_DEBUG) */
732
733 #if defined(AO2_DEBUG)
734 /*!
735  * \internal
736  * \brief Decrement the hash container linked object statistic.
737  * \since 12.0.0
738  *
739  * \param hash Container to operate upon.
740  * \param hash_node Container node unlinking object from.
741  *
742  * \return Nothing
743  */
744 static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
745 {
746         struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
747         struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
748
749         --self->buckets[node->my_bucket].elements;
750 }
751 #endif  /* defined(AO2_DEBUG) */
752
753 /*!
754  * \internal
755  *
756  * \brief Destroy this container.
757  * \since 12.0.0
758  *
759  * \param self Container to operate upon.
760  *
761  * \return Nothing
762  */
763 static void hash_ao2_destroy(struct ao2_container_hash *self)
764 {
765         int idx;
766
767         /* Check that the container no longer has any nodes */
768         for (idx = self->n_buckets; idx--;) {
769                 if (!AST_DLLIST_EMPTY(&self->buckets[idx].list)) {
770                         ast_log(LOG_ERROR, "Node ref leak.  Hash container still has nodes!\n");
771                         ast_assert(0);
772                         break;
773                 }
774         }
775 }
776
777 #if defined(AO2_DEBUG)
778 /*!
779  * \internal
780  * \brief Display contents of the specified container.
781  * \since 12.0.0
782  *
783  * \param self Container to dump.
784  * \param where User data needed by prnt to determine where to put output.
785  * \param prnt Print output callback function to use.
786  * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
787  *
788  * \return Nothing
789  */
790 static void hash_ao2_dump(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
791 {
792 #define FORMAT  "%6s, %16s, %16s, %16s, %16s, %s\n"
793 #define FORMAT2 "%6d, %16p, %16p, %16p, %16p, "
794
795         int bucket;
796         int suppressed_buckets = 0;
797         struct hash_bucket_node *node;
798
799         prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
800
801         prnt(where, FORMAT, "Bucket", "Node", "Prev", "Next", "Obj", "Key");
802         for (bucket = 0; bucket < self->n_buckets; ++bucket) {
803                 node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
804                 if (node) {
805                         suppressed_buckets = 0;
806                         do {
807                                 prnt(where, FORMAT2,
808                                         bucket,
809                                         node,
810                                         AST_DLLIST_PREV(node, links),
811                                         AST_DLLIST_NEXT(node, links),
812                                         node->common.obj);
813                                 if (node->common.obj && prnt_obj) {
814                                         prnt_obj(node->common.obj, where, prnt);
815                                 }
816                                 prnt(where, "\n");
817
818                                 node = AST_DLLIST_NEXT(node, links);
819                         } while (node);
820                 } else if (!suppressed_buckets) {
821                         suppressed_buckets = 1;
822                         prnt(where, "...\n");
823                 }
824         }
825
826 #undef FORMAT
827 #undef FORMAT2
828 }
829 #endif  /* defined(AO2_DEBUG) */
830
831 #if defined(AO2_DEBUG)
832 /*!
833  * \internal
834  * \brief Display statistics of the specified container.
835  * \since 12.0.0
836  *
837  * \param self Container to display statistics.
838  * \param where User data needed by prnt to determine where to put output.
839  * \param prnt Print output callback function to use.
840  *
841  * \note The container is already locked for reading.
842  *
843  * \return Nothing
844  */
845 static void hash_ao2_stats(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt)
846 {
847 #define FORMAT  "%10.10s %10.10s %10.10s\n"
848 #define FORMAT2 "%10d %10d %10d\n"
849
850         int bucket;
851         int suppressed_buckets = 0;
852
853         prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
854
855         prnt(where, FORMAT, "Bucket", "Objects", "Max");
856         for (bucket = 0; bucket < self->n_buckets; ++bucket) {
857                 if (self->buckets[bucket].max_elements) {
858                         suppressed_buckets = 0;
859                         prnt(where, FORMAT2, bucket, self->buckets[bucket].elements,
860                                 self->buckets[bucket].max_elements);
861                 } else if (!suppressed_buckets) {
862                         suppressed_buckets = 1;
863                         prnt(where, "...\n");
864                 }
865         }
866
867 #undef FORMAT
868 #undef FORMAT2
869 }
870 #endif  /* defined(AO2_DEBUG) */
871
872 #if defined(AO2_DEBUG)
873 /*!
874  * \internal
875  * \brief Perform an integrity check on the specified container.
876  * \since 12.0.0
877  *
878  * \param self Container to check integrity.
879  *
880  * \note The container is already locked for reading.
881  *
882  * \retval 0 on success.
883  * \retval -1 on error.
884  */
885 static int hash_ao2_integrity(struct ao2_container_hash *self)
886 {
887         int bucket_exp;
888         int bucket;
889         int count_obj;
890         int count_total_obj;
891         int count_total_node;
892         void *obj_last;
893         struct hash_bucket_node *node;
894         struct hash_bucket_node *prev;
895         struct hash_bucket_node *next;
896
897         count_total_obj = 0;
898         count_total_node = 0;
899
900         /* For each bucket in the container. */
901         for (bucket = 0; bucket < self->n_buckets; ++bucket) {
902                 if (!AST_DLLIST_FIRST(&self->buckets[bucket].list)
903                         && !AST_DLLIST_LAST(&self->buckets[bucket].list)) {
904                         /* The bucket list is empty. */
905                         continue;
906                 }
907
908                 count_obj = 0;
909                 obj_last = NULL;
910
911                 /* Check bucket list links and nodes. */
912                 node = AST_DLLIST_LAST(&self->buckets[bucket].list);
913                 if (!node) {
914                         ast_log(LOG_ERROR, "Bucket %d list tail is NULL when it should not be!\n",
915                                 bucket);
916                         return -1;
917                 }
918                 if (AST_DLLIST_NEXT(node, links)) {
919                         ast_log(LOG_ERROR, "Bucket %d list tail node is not the last node!\n",
920                                 bucket);
921                         return -1;
922                 }
923                 node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
924                 if (!node) {
925                         ast_log(LOG_ERROR, "Bucket %d list head is NULL when it should not be!\n",
926                                 bucket);
927                         return -1;
928                 }
929                 if (AST_DLLIST_PREV(node, links)) {
930                         ast_log(LOG_ERROR, "Bucket %d list head node is not the first node!\n",
931                                 bucket);
932                         return -1;
933                 }
934                 for (; node; node = next) {
935                         /* Check backward link. */
936                         prev = AST_DLLIST_PREV(node, links);
937                         if (prev) {
938                                 if (prev == node) {
939                                         ast_log(LOG_ERROR, "Bucket %d list node's prev pointer points to itself!\n",
940                                                 bucket);
941                                         return -1;
942                                 }
943                                 if (node != AST_DLLIST_NEXT(prev, links)) {
944                                         ast_log(LOG_ERROR, "Bucket %d list node's prev node does not link back!\n",
945                                                 bucket);
946                                         return -1;
947                                 }
948                         } else if (node != AST_DLLIST_FIRST(&self->buckets[bucket].list)) {
949                                 ast_log(LOG_ERROR, "Bucket %d backward list chain is broken!\n",
950                                         bucket);
951                                 return -1;
952                         }
953
954                         /* Check forward link. */
955                         next = AST_DLLIST_NEXT(node, links);
956                         if (next) {
957                                 if (next == node) {
958                                         ast_log(LOG_ERROR, "Bucket %d list node's next pointer points to itself!\n",
959                                                 bucket);
960                                         return -1;
961                                 }
962                                 if (node != AST_DLLIST_PREV(next, links)) {
963                                         ast_log(LOG_ERROR, "Bucket %d list node's next node does not link back!\n",
964                                                 bucket);
965                                         return -1;
966                                 }
967                         } else if (node != AST_DLLIST_LAST(&self->buckets[bucket].list)) {
968                                 ast_log(LOG_ERROR, "Bucket %d forward list chain is broken!\n",
969                                         bucket);
970                                 return -1;
971                         }
972
973                         if (bucket != node->my_bucket) {
974                                 ast_log(LOG_ERROR, "Bucket %d node claims to be in bucket %d!\n",
975                                         bucket, node->my_bucket);
976                                 return -1;
977                         }
978
979                         ++count_total_node;
980                         if (!node->common.obj) {
981                                 /* Node is empty. */
982                                 continue;
983                         }
984                         ++count_obj;
985
986                         /* Check container hash key for expected bucket. */
987                         bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_SEARCH_OBJECT));
988                         bucket_exp %= self->n_buckets;
989                         if (bucket != bucket_exp) {
990                                 ast_log(LOG_ERROR, "Bucket %d node hashes to bucket %d!\n",
991                                         bucket, bucket_exp);
992                                 return -1;
993                         }
994
995                         /* Check sort if configured. */
996                         if (self->common.sort_fn) {
997                                 if (obj_last
998                                         && self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
999                                         ast_log(LOG_ERROR, "Bucket %d nodes out of sorted order!\n",
1000                                                 bucket);
1001                                         return -1;
1002                                 }
1003                                 obj_last = node->common.obj;
1004                         }
1005                 }
1006
1007                 /* Check bucket obj count statistic. */
1008                 if (count_obj != self->buckets[bucket].elements) {
1009                         ast_log(LOG_ERROR, "Bucket %d object count of %d does not match stat of %d!\n",
1010                                 bucket, count_obj, self->buckets[bucket].elements);
1011                         return -1;
1012                 }
1013
1014                 /* Accumulate found object counts. */
1015                 count_total_obj += count_obj;
1016         }
1017
1018         /* Check total obj count. */
1019         if (count_total_obj != ao2_container_count(&self->common)) {
1020                 ast_log(LOG_ERROR,
1021                         "Total object count of %d does not match ao2_container_count() of %d!\n",
1022                         count_total_obj, ao2_container_count(&self->common));
1023                 return -1;
1024         }
1025
1026         /* Check total node count. */
1027         if (count_total_node != self->common.nodes) {
1028                 ast_log(LOG_ERROR, "Total node count of %d does not match stat of %d!\n",
1029                         count_total_node, self->common.nodes);
1030                 return -1;
1031         }
1032
1033         return 0;
1034 }
1035 #endif  /* defined(AO2_DEBUG) */
1036
1037 /*! Hash container virtual method table. */
1038 static const struct ao2_container_methods v_table_hash = {
1039         .alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) hash_ao2_alloc_empty_clone,
1040         .alloc_empty_clone_debug =
1041                 (ao2_container_alloc_empty_clone_debug_fn) hash_ao2_alloc_empty_clone_debug,
1042         .new_node = (ao2_container_new_node_fn) hash_ao2_new_node,
1043         .insert = (ao2_container_insert_fn) hash_ao2_insert_node,
1044         .traverse_first = (ao2_container_find_first_fn) hash_ao2_find_first,
1045         .traverse_next = (ao2_container_find_next_fn) hash_ao2_find_next,
1046         .iterator_next = (ao2_iterator_next_fn) hash_ao2_iterator_next,
1047         .destroy = (ao2_container_destroy_fn) hash_ao2_destroy,
1048 #if defined(AO2_DEBUG)
1049         .link_stat = hash_ao2_link_node_stat,
1050         .unlink_stat = hash_ao2_unlink_node_stat,
1051         .dump = (ao2_container_display) hash_ao2_dump,
1052         .stats = (ao2_container_statistics) hash_ao2_stats,
1053         .integrity = (ao2_container_integrity) hash_ao2_integrity,
1054 #endif  /* defined(AO2_DEBUG) */
1055 };
1056
1057 /*!
1058  * \brief always zero hash function
1059  *
1060  * it is convenient to have a hash function that always returns 0.
1061  * This is basically used when we want to have a container that is
1062  * a simple linked list.
1063  *
1064  * \returns 0
1065  */
1066 static int hash_zero(const void *user_obj, const int flags)
1067 {
1068         return 0;
1069 }
1070
1071 /*!
1072  * \brief Initialize a hash container with the desired number of buckets.
1073  *
1074  * \param self Container to initialize.
1075  * \param options Container behaviour options (See enum ao2_container_opts)
1076  * \param n_buckets Number of buckets for hash
1077  * \param hash_fn Pointer to a function computing a hash value.
1078  * \param sort_fn Pointer to a sort function.
1079  * \param cmp_fn Pointer to a compare function used by ao2_find.
1080  *
1081  * \return A pointer to a struct container.
1082  */
1083 static struct ao2_container *hash_ao2_container_init(
1084         struct ao2_container_hash *self, unsigned int options, unsigned int n_buckets,
1085         ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
1086 {
1087         if (!self) {
1088                 return NULL;
1089         }
1090
1091         self->common.v_table = &v_table_hash;
1092         self->common.sort_fn = sort_fn;
1093         self->common.cmp_fn = cmp_fn;
1094         self->common.options = options;
1095         self->hash_fn = hash_fn ? hash_fn : hash_zero;
1096         self->n_buckets = n_buckets;
1097
1098 #ifdef AO2_DEBUG
1099         ast_atomic_fetchadd_int(&ao2.total_containers, 1);
1100 #endif  /* defined(AO2_DEBUG) */
1101
1102         return (struct ao2_container *) self;
1103 }
1104
1105 struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
1106         unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
1107         ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
1108 {
1109         unsigned int num_buckets;
1110         size_t container_size;
1111         struct ao2_container_hash *self;
1112
1113         num_buckets = hash_fn ? n_buckets : 1;
1114         container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
1115
1116         self = ao2_t_alloc_options(container_size, container_destruct, ao2_options,
1117                 "New hash container");
1118         return hash_ao2_container_init(self, container_options, num_buckets,
1119                 hash_fn, sort_fn, cmp_fn);
1120 }
1121
1122 struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
1123         unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
1124         ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
1125         const char *tag, const char *file, int line, const char *func, int ref_debug)
1126 {
1127         unsigned int num_buckets;
1128         size_t container_size;
1129         struct ao2_container_hash *self;
1130
1131         num_buckets = hash_fn ? n_buckets : 1;
1132         container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
1133
1134         self = __ao2_alloc_debug(container_size,
1135                 ref_debug ? container_destruct_debug : container_destruct, ao2_options,
1136                 tag, file, line, func, ref_debug);
1137         return hash_ao2_container_init(self, container_options, num_buckets, hash_fn,
1138                 sort_fn, cmp_fn);
1139 }
1140
1141 struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
1142         unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
1143 {
1144         return __ao2_container_alloc_hash(ao2_options, container_options, 1, NULL, sort_fn,
1145                 cmp_fn);
1146 }
1147
1148 struct ao2_container *__ao2_container_alloc_list_debug(unsigned int ao2_options,
1149         unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
1150         const char *tag, const char *file, int line, const char *func, int ref_debug)
1151 {
1152         return __ao2_container_alloc_hash_debug(ao2_options, container_options, 1, NULL,
1153                 sort_fn, cmp_fn, tag, file, line, func, ref_debug);
1154 }
1155