604e6a1ae41ba1dbaae6093c986f540b82bb3083
[asterisk/asterisk.git] / main / astobj2.c
1 /*
2  * astobj2 - replacement containers for asterisk data structures.
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 Functions implementing astobj2 objects.
20  *
21  * \author Richard Mudgett <rmudgett@digium.com>
22  */
23
24 /*** MODULEINFO
25         <support_level>core</support_level>
26  ***/
27
28 #include "asterisk.h"
29
30 ASTERISK_REGISTER_FILE()
31
32 #include "asterisk/_private.h"
33 #include "asterisk/astobj2.h"
34 #include "astobj2_private.h"
35 #include "astobj2_container_private.h"
36 #include "asterisk/cli.h"
37 #include "asterisk/paths.h"
38
39 /* Use ast_log_safe in place of ast_log. */
40 #define ast_log ast_log_safe
41
42 static FILE *ref_log;
43
44 /*!
45  * astobj2 objects are always preceded by this data structure,
46  * which contains a reference counter,
47  * option flags and a pointer to a destructor.
48  * The refcount is used to decide when it is time to
49  * invoke the destructor.
50  * The magic number is used for consistency check.
51  */
52 struct __priv_data {
53         int ref_counter;
54         ao2_destructor_fn destructor_fn;
55         /*! This field is used for astobj2 and ao2_weakproxy objects to reference each other */
56         void *weakptr;
57         /*! User data size for stats */
58         size_t data_size;
59         /*! The ao2 object option flags */
60         uint32_t options;
61         /*! magic number.  This is used to verify that a pointer passed in is a
62          *  valid astobj2 or ao2_weak reference */
63         uint32_t magic;
64 };
65
66 #define AO2_MAGIC       0xa570b123
67 #define AO2_WEAK        0xa570b122
68 #define IS_AO2_MAGIC_BAD(p) (AO2_MAGIC != (p->priv_data.magic | 1))
69
70 /*!
71  * What an astobj2 object looks like: fixed-size private data
72  * followed by variable-size user data.
73  */
74 struct astobj2 {
75         struct __priv_data priv_data;
76         void *user_data[0];
77 };
78
79 struct ao2_weakproxy_notification {
80         ao2_weakproxy_notification_cb cb;
81         void *data;
82         AST_LIST_ENTRY(ao2_weakproxy_notification) list;
83 };
84
85 static void weakproxy_run_callbacks(struct ao2_weakproxy *weakproxy);
86
87 struct ao2_lock_priv {
88         ast_mutex_t lock;
89 };
90
91 /* AstObj2 with recursive lock. */
92 struct astobj2_lock {
93         struct ao2_lock_priv mutex;
94         struct __priv_data priv_data;
95         void *user_data[0];
96 };
97
98 struct ao2_rwlock_priv {
99         ast_rwlock_t lock;
100         /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
101         int num_lockers;
102 };
103
104 /* AstObj2 with RW lock. */
105 struct astobj2_rwlock {
106         struct ao2_rwlock_priv rwlock;
107         struct __priv_data priv_data;
108         void *user_data[0];
109 };
110
111 struct ao2_lockobj_priv {
112         void *lock;
113 };
114
115 /* AstObj2 with locking provided by a separate object. */
116 struct astobj2_lockobj {
117         struct ao2_lockobj_priv lockobj;
118         struct __priv_data priv_data;
119         void *user_data[0];
120 };
121
122 #ifdef AO2_DEBUG
123 struct ao2_stats ao2;
124 #endif
125
126 #define INTERNAL_OBJ_MUTEX(user_data) \
127         ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
128
129 #define INTERNAL_OBJ_RWLOCK(user_data) \
130         ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
131
132 #define INTERNAL_OBJ_LOCKOBJ(user_data) \
133         ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj)))
134
135 #define INTERNAL_OBJ(user_data) \
136         (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))
137
138 /*!
139  * \brief convert from a pointer _p to a user-defined object
140  *
141  * \return the pointer to the astobj2 structure
142  */
143 #define __INTERNAL_OBJ_CHECK(user_data, file, line, func) \
144         ({ \
145                 struct astobj2 *p ## __LINE__; \
146                 if (!user_data \
147                         || !(p ## __LINE__ = INTERNAL_OBJ(user_data)) \
148                         || IS_AO2_MAGIC_BAD(p ## __LINE__)) { \
149                         log_bad_ao2(user_data, file, line, func); \
150                         p ## __LINE__ = NULL; \
151                 } \
152                 (p ## __LINE__); \
153         })
154
155 #define INTERNAL_OBJ_CHECK(user_data) \
156         __INTERNAL_OBJ_CHECK(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)
157
158 /*!
159  * \brief convert from a pointer _p to an astobj2 object
160  *
161  * \return the pointer to the user-defined portion.
162  */
163 #define EXTERNAL_OBJ(_p)        ((_p) == NULL ? NULL : (_p)->user_data)
164
165 int internal_is_ao2_object(void *user_data)
166 {
167         struct astobj2 *p;
168
169         if (!user_data) {
170                 return 0;
171         }
172
173         p = INTERNAL_OBJ(user_data);
174
175         return !p || IS_AO2_MAGIC_BAD(p) ? 0 : 1;
176 }
177
178 void log_bad_ao2(void *user_data, const char *file, int line, const char *func)
179 {
180         struct astobj2 *p;
181
182         if (!user_data) {
183                 ast_log(__LOG_ERROR, file, line, func, "user_data is NULL\n");
184                 return;
185         }
186
187         p = INTERNAL_OBJ(user_data);
188         if (p->priv_data.magic) {
189                 ast_log(__LOG_ERROR, file, line, func,
190                         "bad magic number 0x%x for object %p\n",
191                         p->priv_data.magic, user_data);
192         } else {
193                 ast_log(__LOG_ERROR, file, line, func,
194                         "bad magic number for object %p. Object is likely destroyed.\n",
195                         user_data);
196         }
197 }
198
199 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
200 {
201         struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
202         struct astobj2_lock *obj_mutex;
203         struct astobj2_rwlock *obj_rwlock;
204         struct astobj2_lockobj *obj_lockobj;
205         int res = 0;
206
207         if (obj == NULL) {
208                 ast_assert(0);
209                 return -1;
210         }
211
212         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
213         case AO2_ALLOC_OPT_LOCK_MUTEX:
214                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
215                 res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
216 #ifdef AO2_DEBUG
217                 if (!res) {
218                         ast_atomic_fetchadd_int(&ao2.total_locked, 1);
219                 }
220 #endif
221                 break;
222         case AO2_ALLOC_OPT_LOCK_RWLOCK:
223                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
224                 switch (lock_how) {
225                 case AO2_LOCK_REQ_MUTEX:
226                 case AO2_LOCK_REQ_WRLOCK:
227                         res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
228                         if (!res) {
229                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
230 #ifdef AO2_DEBUG
231                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
232 #endif
233                         }
234                         break;
235                 case AO2_LOCK_REQ_RDLOCK:
236                         res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
237                         if (!res) {
238                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
239 #ifdef AO2_DEBUG
240                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
241 #endif
242                         }
243                         break;
244                 }
245                 break;
246         case AO2_ALLOC_OPT_LOCK_NOLOCK:
247                 /* The ao2 object has no lock. */
248                 break;
249         case AO2_ALLOC_OPT_LOCK_OBJ:
250                 obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
251                 res = __ao2_lock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var);
252                 break;
253         default:
254                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
255                         user_data);
256                 return -1;
257         }
258
259         return res;
260 }
261
262 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
263 {
264         struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
265         struct astobj2_lock *obj_mutex;
266         struct astobj2_rwlock *obj_rwlock;
267         struct astobj2_lockobj *obj_lockobj;
268         int res = 0;
269         int current_value;
270
271         if (obj == NULL) {
272                 ast_assert(0);
273                 return -1;
274         }
275
276         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
277         case AO2_ALLOC_OPT_LOCK_MUTEX:
278                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
279                 res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
280 #ifdef AO2_DEBUG
281                 if (!res) {
282                         ast_atomic_fetchadd_int(&ao2.total_locked, -1);
283                 }
284 #endif
285                 break;
286         case AO2_ALLOC_OPT_LOCK_RWLOCK:
287                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
288
289                 current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
290                 if (current_value < 0) {
291                         /* It was a WRLOCK that we are unlocking.  Fix the count. */
292                         ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
293                 }
294                 res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
295 #ifdef AO2_DEBUG
296                 if (!res) {
297                         ast_atomic_fetchadd_int(&ao2.total_locked, -1);
298                 }
299 #endif
300                 break;
301         case AO2_ALLOC_OPT_LOCK_NOLOCK:
302                 /* The ao2 object has no lock. */
303                 break;
304         case AO2_ALLOC_OPT_LOCK_OBJ:
305                 obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
306                 res = __ao2_unlock(obj_lockobj->lockobj.lock, file, func, line, var);
307                 break;
308         default:
309                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
310                         user_data);
311                 res = -1;
312                 break;
313         }
314         return res;
315 }
316
317 int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
318 {
319         struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
320         struct astobj2_lock *obj_mutex;
321         struct astobj2_rwlock *obj_rwlock;
322         struct astobj2_lockobj *obj_lockobj;
323         int res = 0;
324
325         if (obj == NULL) {
326                 ast_assert(0);
327                 return -1;
328         }
329
330         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
331         case AO2_ALLOC_OPT_LOCK_MUTEX:
332                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
333                 res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
334 #ifdef AO2_DEBUG
335                 if (!res) {
336                         ast_atomic_fetchadd_int(&ao2.total_locked, 1);
337                 }
338 #endif
339                 break;
340         case AO2_ALLOC_OPT_LOCK_RWLOCK:
341                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
342                 switch (lock_how) {
343                 case AO2_LOCK_REQ_MUTEX:
344                 case AO2_LOCK_REQ_WRLOCK:
345                         res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
346                         if (!res) {
347                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
348 #ifdef AO2_DEBUG
349                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
350 #endif
351                         }
352                         break;
353                 case AO2_LOCK_REQ_RDLOCK:
354                         res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
355                         if (!res) {
356                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
357 #ifdef AO2_DEBUG
358                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
359 #endif
360                         }
361                         break;
362                 }
363                 break;
364         case AO2_ALLOC_OPT_LOCK_NOLOCK:
365                 /* The ao2 object has no lock. */
366                 return 0;
367         case AO2_ALLOC_OPT_LOCK_OBJ:
368                 obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
369                 res = __ao2_trylock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var);
370                 break;
371         default:
372                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
373                         user_data);
374                 return -1;
375         }
376
377
378         return res;
379 }
380
381 /*!
382  * \internal
383  * \brief Adjust an object's lock to the requested level.
384  *
385  * \param user_data An ao2 object to adjust lock level.
386  * \param lock_how What level to adjust lock.
387  * \param keep_stronger TRUE if keep original lock level if it is stronger.
388  *
389  * \pre The ao2 object is already locked.
390  *
391  * \details
392  * An ao2 object with a RWLOCK will have its lock level adjusted
393  * to the specified level if it is not already there.  An ao2
394  * object with a different type of lock is not affected.
395  *
396  * \return Original lock level.
397  */
398 enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
399 {
400         struct astobj2 *obj = INTERNAL_OBJ(user_data);
401         struct astobj2_rwlock *obj_rwlock;
402         struct astobj2_lockobj *obj_lockobj;
403         enum ao2_lock_req orig_lock;
404
405         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
406         case AO2_ALLOC_OPT_LOCK_RWLOCK:
407                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
408                 if (obj_rwlock->rwlock.num_lockers < 0) {
409                         orig_lock = AO2_LOCK_REQ_WRLOCK;
410                 } else {
411                         orig_lock = AO2_LOCK_REQ_RDLOCK;
412                 }
413                 switch (lock_how) {
414                 case AO2_LOCK_REQ_MUTEX:
415                         lock_how = AO2_LOCK_REQ_WRLOCK;
416                         /* Fall through */
417                 case AO2_LOCK_REQ_WRLOCK:
418                         if (lock_how != orig_lock) {
419                                 /* Switch from read lock to write lock. */
420                                 ao2_unlock(user_data);
421                                 ao2_wrlock(user_data);
422                         }
423                         break;
424                 case AO2_LOCK_REQ_RDLOCK:
425                         if (!keep_stronger && lock_how != orig_lock) {
426                                 /* Switch from write lock to read lock. */
427                                 ao2_unlock(user_data);
428                                 ao2_rdlock(user_data);
429                         }
430                         break;
431                 }
432                 break;
433         case AO2_ALLOC_OPT_LOCK_OBJ:
434                 obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
435                 orig_lock = __adjust_lock(obj_lockobj->lockobj.lock, lock_how, keep_stronger);
436                 break;
437         default:
438                 ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
439                 /* Fall through */
440         case AO2_ALLOC_OPT_LOCK_NOLOCK:
441         case AO2_ALLOC_OPT_LOCK_MUTEX:
442                 orig_lock = AO2_LOCK_REQ_MUTEX;
443                 break;
444         }
445
446         return orig_lock;
447 }
448
449 void *ao2_object_get_lockaddr(void *user_data)
450 {
451         struct astobj2 *obj;
452         struct astobj2_lock *obj_mutex;
453
454         obj = INTERNAL_OBJ_CHECK(user_data);
455
456         if (obj == NULL) {
457                 ast_assert(0);
458                 return NULL;
459         }
460
461         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
462         case AO2_ALLOC_OPT_LOCK_MUTEX:
463                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
464                 return &obj_mutex->mutex.lock;
465         default:
466                 break;
467         }
468
469         return NULL;
470 }
471
472 int __ao2_ref(void *user_data, int delta,
473         const char *tag, const char *file, int line, const char *func)
474 {
475         struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
476         struct astobj2_lock *obj_mutex;
477         struct astobj2_rwlock *obj_rwlock;
478         struct astobj2_lockobj *obj_lockobj;
479         int current_value;
480         int ret;
481         void *weakproxy = NULL;
482
483         if (obj == NULL) {
484                 if (ref_log && user_data) {
485                         fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
486                                 user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
487                         fflush(ref_log);
488                 }
489                 ast_assert(0);
490                 return -1;
491         }
492
493         /* if delta is 0, just return the refcount */
494         if (delta == 0) {
495                 return obj->priv_data.ref_counter;
496         }
497
498         if (delta < 0 && obj->priv_data.magic == AO2_MAGIC && (weakproxy = obj->priv_data.weakptr)) {
499                 ao2_lock(weakproxy);
500         }
501
502         /* we modify with an atomic operation the reference counter */
503         ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
504         current_value = ret + delta;
505
506 #ifdef AO2_DEBUG
507         ast_atomic_fetchadd_int(&ao2.total_refs, delta);
508 #endif
509
510         if (weakproxy) {
511                 if (current_value == 1) {
512                         /* The only remaining reference is the one owned by the weak object */
513                         struct astobj2 *internal_weakproxy;
514
515                         internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
516
517                         /* Unlink the obj from the weak proxy */
518                         internal_weakproxy->priv_data.weakptr = NULL;
519                         obj->priv_data.weakptr = NULL;
520
521                         /* Notify the subscribers that weakproxy now points to NULL. */
522                         weakproxy_run_callbacks(weakproxy);
523
524                         /* weak is already unlinked from obj so this won't recurse */
525                         ao2_ref(user_data, -1);
526                 }
527
528                 ao2_unlock(weakproxy);
529
530                 if (current_value == 1) {
531                         ao2_ref(weakproxy, -1);
532                 }
533         }
534
535         if (0 < current_value) {
536                 /* The object still lives. */
537                 if (ref_log && tag) {
538                         fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data,
539                                 (delta < 0 ? "" : "+"), delta, ast_get_tid(),
540                                 file, line, func, ret, tag);
541                         fflush(ref_log);
542                 }
543                 return ret;
544         }
545
546         /* this case must never happen */
547         if (current_value < 0) {
548                 ast_log(__LOG_ERROR, file, line, func,
549                         "Invalid refcount %d on ao2 object %p\n", current_value, user_data);
550                 if (ref_log) {
551                         /* Log to ref_log invalid even if (tag == NULL) */
552                         fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
553                                 user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
554                         fflush(ref_log);
555                 }
556                 ast_assert(0);
557                 /* stop here even if assert doesn't DO_CRASH */
558                 return -1;
559         }
560
561         /* last reference, destroy the object */
562         if (obj->priv_data.destructor_fn != NULL) {
563                 obj->priv_data.destructor_fn(user_data);
564         }
565
566 #ifdef AO2_DEBUG
567         ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
568         ast_atomic_fetchadd_int(&ao2.total_objects, -1);
569 #endif
570
571         /* In case someone uses an object after it's been freed */
572         obj->priv_data.magic = 0;
573
574         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
575         case AO2_ALLOC_OPT_LOCK_MUTEX:
576                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
577                 ast_mutex_destroy(&obj_mutex->mutex.lock);
578
579                 ast_free(obj_mutex);
580                 break;
581         case AO2_ALLOC_OPT_LOCK_RWLOCK:
582                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
583                 ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
584
585                 ast_free(obj_rwlock);
586                 break;
587         case AO2_ALLOC_OPT_LOCK_NOLOCK:
588                 ast_free(obj);
589                 break;
590         case AO2_ALLOC_OPT_LOCK_OBJ:
591                 obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
592                 ao2_t_ref(obj_lockobj->lockobj.lock, -1, "release lockobj");
593
594                 ast_free(obj_lockobj);
595                 break;
596         default:
597                 ast_log(__LOG_ERROR, file, line, func,
598                         "Invalid lock option on ao2 object %p\n", user_data);
599                 break;
600         }
601
602         if (ref_log && tag) {
603                 fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
604                         user_data, delta, ast_get_tid(), file, line, func, tag);
605                 fflush(ref_log);
606         }
607
608         return ret;
609 }
610
611 void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
612 {
613         if (obj) {
614                 __ao2_ref(obj, -1, tag, file, line, function);
615         }
616 }
617
618 void __ao2_cleanup(void *obj)
619 {
620         if (obj) {
621                 ao2_ref(obj, -1);
622         }
623 }
624
625 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
626         void *lockobj, const char *tag, const char *file, int line, const char *func)
627 {
628         /* allocation */
629         struct astobj2 *obj;
630         struct astobj2_lock *obj_mutex;
631         struct astobj2_rwlock *obj_rwlock;
632         struct astobj2_lockobj *obj_lockobj;
633
634         switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
635         case AO2_ALLOC_OPT_LOCK_MUTEX:
636                 obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func);
637                 if (obj_mutex == NULL) {
638                         return NULL;
639                 }
640
641                 ast_mutex_init(&obj_mutex->mutex.lock);
642                 obj = (struct astobj2 *) &obj_mutex->priv_data;
643                 break;
644         case AO2_ALLOC_OPT_LOCK_RWLOCK:
645                 obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func);
646                 if (obj_rwlock == NULL) {
647                         return NULL;
648                 }
649
650                 ast_rwlock_init(&obj_rwlock->rwlock.lock);
651                 obj = (struct astobj2 *) &obj_rwlock->priv_data;
652                 break;
653         case AO2_ALLOC_OPT_LOCK_NOLOCK:
654                 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func);
655                 if (obj == NULL) {
656                         return NULL;
657                 }
658                 break;
659         case AO2_ALLOC_OPT_LOCK_OBJ:
660                 lockobj = ao2_t_bump(lockobj, "set lockobj");
661                 if (!lockobj) {
662                         ast_log(__LOG_ERROR, file, line, func, "AO2_ALLOC_OPT_LOCK_OBJ requires a non-NULL lockobj.\n");
663                         return NULL;
664                 }
665
666                 obj_lockobj = __ast_calloc(1, sizeof(*obj_lockobj) + data_size, file, line, func);
667                 if (obj_lockobj == NULL) {
668                         ao2_t_ref(lockobj, -1, "release lockobj for failed alloc");
669                         return NULL;
670                 }
671
672                 obj_lockobj->lockobj.lock = lockobj;
673                 obj = (struct astobj2 *) &obj_lockobj->priv_data;
674                 break;
675         default:
676                 /* Invalid option value. */
677                 ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
678                 return NULL;
679         }
680
681         /* Initialize common ao2 values. */
682         obj->priv_data.ref_counter = 1;
683         obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
684         obj->priv_data.data_size = data_size;
685         obj->priv_data.options = options;
686         obj->priv_data.magic = AO2_MAGIC;
687
688 #ifdef AO2_DEBUG
689         ast_atomic_fetchadd_int(&ao2.total_objects, 1);
690         ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
691         ast_atomic_fetchadd_int(&ao2.total_refs, 1);
692 #endif
693
694         if (ref_log && tag) {
695                 fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n",
696                         EXTERNAL_OBJ(obj), ast_get_tid(), file, line, func, tag);
697                 fflush(ref_log);
698         }
699
700         /* return a pointer to the user data */
701         return EXTERNAL_OBJ(obj);
702 }
703
704 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
705         const char *tag, const char *file, int line, const char *func)
706 {
707         return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func);
708 }
709
710 void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj,
711         const char *tag, const char *file, int line, const char *func)
712 {
713         return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj,
714                 tag, file, line, func);
715 }
716
717 unsigned int ao2_options_get(void *obj)
718 {
719         struct astobj2 *orig_obj;
720
721         orig_obj = INTERNAL_OBJ_CHECK(obj);
722         if (!orig_obj) {
723                 return 0;
724         }
725         return orig_obj->priv_data.options;
726 }
727
728
729 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
730 {
731         if (!holder) {
732                 /* For sanity */
733                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
734                 ast_assert(0);
735                 return;
736         }
737         if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
738                 /* Could not get the write lock. */
739                 ast_assert(0);
740                 return;
741         }
742
743         /* Release the held ao2 object. */
744         if (holder->obj) {
745                 __ao2_ref(holder->obj, -1, tag, file, line, func);
746                 holder->obj = NULL;
747         }
748
749         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
750 }
751
752 void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name)
753 {
754         void *obj_old;
755
756         if (!holder) {
757                 /* For sanity */
758                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
759                 ast_assert(0);
760                 return NULL;
761         }
762         if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
763                 /* Could not get the write lock. */
764                 ast_assert(0);
765                 return NULL;
766         }
767
768         if (obj) {
769                 __ao2_ref(obj, +1, tag, file, line, func);
770         }
771         obj_old = holder->obj;
772         holder->obj = obj;
773
774         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
775
776         return obj_old;
777 }
778
779 int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name)
780 {
781         void *obj_old;
782
783         obj_old = __ao2_global_obj_replace(holder, obj, tag, file, line, func, name);
784         if (obj_old) {
785                 __ao2_ref(obj_old, -1, tag, file, line, func);
786                 return 1;
787         }
788         return 0;
789 }
790
791 void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
792 {
793         void *obj;
794
795         if (!holder) {
796                 /* For sanity */
797                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
798                 ast_assert(0);
799                 return NULL;
800         }
801
802         if (__ast_rwlock_rdlock(file, line, func, &holder->lock, name)) {
803                 /* Could not get the read lock. */
804                 ast_assert(0);
805                 return NULL;
806         }
807
808         obj = holder->obj;
809         if (obj) {
810                 __ao2_ref(obj, +1, tag, file, line, func);
811         }
812
813         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
814
815         return obj;
816 }
817
818
819 static void weakproxy_run_callbacks(struct ao2_weakproxy *weakproxy)
820 {
821         struct ao2_weakproxy_notification *destroyed_cb;
822
823         while ((destroyed_cb = AST_LIST_REMOVE_HEAD(&weakproxy->destroyed_cb, list))) {
824                 destroyed_cb->cb(weakproxy, destroyed_cb->data);
825                 ast_free(destroyed_cb);
826         }
827 }
828
829 void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn,
830         const char *tag, const char *file, int line, const char *func)
831 {
832         struct ao2_weakproxy *weakproxy;
833
834         if (data_size < sizeof(*weakproxy)) {
835                 ast_assert(0);
836                 ast_log(LOG_ERROR, "Requested data_size smaller than minimum.\n");
837                 return NULL;
838         }
839
840         weakproxy = __ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_MUTEX,
841                 tag, file, line, func);
842
843         if (weakproxy) {
844                 struct astobj2 *weakproxy_internal;
845
846                 /* Just created weakproxy, no need to check if it's valid. */
847                 weakproxy_internal = INTERNAL_OBJ(weakproxy);
848                 weakproxy_internal->priv_data.magic = AO2_WEAK;
849         }
850
851         return weakproxy;
852 }
853
854 int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
855         const char *tag, const char *file, int line, const char *func)
856 {
857         struct astobj2 *weakproxy_internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
858         struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
859         int ret = -1;
860
861         if (!weakproxy_internal
862                 || weakproxy_internal->priv_data.magic != AO2_WEAK) {
863                 return -1;
864         }
865
866         if (!obj_internal
867                 || obj_internal->priv_data.weakptr
868                 || obj_internal->priv_data.magic != AO2_MAGIC) {
869                 return -1;
870         }
871
872         if (!(flags & OBJ_NOLOCK)) {
873                 ao2_lock(weakproxy);
874         }
875
876         if (!weakproxy_internal->priv_data.weakptr) {
877                 __ao2_ref(obj, +1, tag, file, line, func);
878                 __ao2_ref(weakproxy, +1, tag, file, line, func);
879
880                 weakproxy_internal->priv_data.weakptr = obj;
881                 obj_internal->priv_data.weakptr = weakproxy;
882
883                 ret = 0;
884         }
885
886         if (!(flags & OBJ_NOLOCK)) {
887                 ao2_unlock(weakproxy);
888                 /* It is possible for obj to be accessed now.  It's allowed
889                  * for weakproxy to already be in a container.  Another thread
890                  * could have been waiting for a lock on weakproxy to retreive
891                  * the object.
892                  */
893         }
894
895         return ret;
896 }
897
898 int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags,
899         const char *tag, const char *file, int line, const char *func)
900 {
901         struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
902         int ret = -1;
903
904         if (!internal || internal->priv_data.magic != AO2_WEAK) {
905                 /* This method is meant to be run on weakproxy objects! */
906                 return -2;
907         }
908
909         /* We have a weak object, grab lock. */
910         if (!(flags & OBJ_NOLOCK)) {
911                 ao2_lock(weakproxy);
912         }
913
914         if (internal->priv_data.weakptr) {
915                 ret = __ao2_ref(internal->priv_data.weakptr, delta, tag, file, line, func);
916         }
917
918         if (!(flags & OBJ_NOLOCK)) {
919                 ao2_unlock(weakproxy);
920         }
921
922         return ret;
923 }
924
925 void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
926         const char *tag, const char *file, int line, const char *func)
927 {
928         struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
929         void *obj;
930
931         if (!internal || internal->priv_data.magic != AO2_WEAK) {
932                 /* This method is meant to be run on weakproxy objects! */
933                 return NULL;
934         }
935
936         /* We have a weak object, grab reference to object within lock */
937         if (!(flags & OBJ_NOLOCK)) {
938                 ao2_lock(weakproxy);
939         }
940
941         obj = internal->priv_data.weakptr;
942         if (obj) {
943                 __ao2_ref(obj, +1, tag, file, line, func);
944         }
945
946         if (!(flags & OBJ_NOLOCK)) {
947                 ao2_unlock(weakproxy);
948         }
949
950         return obj;
951 }
952
953 void *__ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
954 {
955         struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
956
957         if (!obj_internal || obj_internal->priv_data.magic != AO2_MAGIC) {
958                 /* This method is meant to be run on normal ao2 objects! */
959                 return NULL;
960         }
961
962         if (!obj_internal->priv_data.weakptr) {
963                 return NULL;
964         }
965
966         __ao2_ref(obj_internal->priv_data.weakptr, +1, tag, file, line, func);
967         return obj_internal->priv_data.weakptr;
968 }
969
970 int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
971 {
972         struct astobj2 *weakproxy_internal = INTERNAL_OBJ_CHECK(weakproxy);
973         int ret = -1;
974
975         if (!weakproxy_internal || weakproxy_internal->priv_data.magic != AO2_WEAK) {
976                 return -1;
977         }
978
979         if (!(flags & OBJ_NOLOCK)) {
980                 ao2_lock(weakproxy);
981         }
982
983         if (weakproxy_internal->priv_data.weakptr) {
984                 struct ao2_weakproxy *weak = weakproxy;
985                 struct ao2_weakproxy_notification *sub = ast_calloc(1, sizeof(*sub));
986
987                 if (sub) {
988                         sub->cb = cb;
989                         sub->data = data;
990                         AST_LIST_INSERT_HEAD(&weak->destroyed_cb, sub, list);
991                         ret = 0;
992                 }
993         } else {
994                 cb(weakproxy, data);
995                 ret = 0;
996         }
997
998         if (!(flags & OBJ_NOLOCK)) {
999                 ao2_unlock(weakproxy);
1000         }
1001
1002         return ret;
1003 }
1004
1005 int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
1006 {
1007         struct astobj2 *internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
1008         struct ao2_weakproxy *weak;
1009         struct ao2_weakproxy_notification *sub;
1010         int ret = 0;
1011
1012         if (!internal_weakproxy || internal_weakproxy->priv_data.magic != AO2_WEAK || !destroyed_cb) {
1013                 return -1;
1014         }
1015
1016         if (!(flags & OBJ_NOLOCK)) {
1017                 ao2_lock(weakproxy);
1018         }
1019
1020         weak = weakproxy;
1021         AST_LIST_TRAVERSE_SAFE_BEGIN(&weak->destroyed_cb, sub, list) {
1022                 if (sub->cb == destroyed_cb && sub->data == data) {
1023                         AST_LIST_REMOVE_CURRENT(list);
1024                         ast_free(sub);
1025                         ret++;
1026                         if (!(flags & OBJ_MULTIPLE)) {
1027                                 break;
1028                         }
1029                 }
1030         }
1031         AST_LIST_TRAVERSE_SAFE_END;
1032
1033         if (!(flags & OBJ_NOLOCK)) {
1034                 ao2_unlock(weakproxy);
1035         }
1036
1037         return ret;
1038 }
1039
1040
1041 #ifdef AO2_DEBUG
1042 static int print_cb(void *obj, void *arg, int flag)
1043 {
1044         struct ast_cli_args *a = (struct ast_cli_args *) arg;
1045         char *s = (char *)obj;
1046
1047         ast_cli(a->fd, "string <%s>\n", s);
1048         return 0;
1049 }
1050
1051 /*
1052  * Print stats
1053  */
1054 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1055 {
1056         switch (cmd) {
1057         case CLI_INIT:
1058                 e->command = "astobj2 show stats";
1059                 e->usage = "Usage: astobj2 show stats\n"
1060                            "       Show astobj2 show stats\n";
1061                 return NULL;
1062         case CLI_GENERATE:
1063                 return NULL;
1064         }
1065         ast_cli(a->fd, "Objects    : %d\n", ao2.total_objects);
1066         ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
1067         ast_cli(a->fd, "Memory     : %d\n", ao2.total_mem);
1068         ast_cli(a->fd, "Locked     : %d\n", ao2.total_locked);
1069         ast_cli(a->fd, "Refs       : %d\n", ao2.total_refs);
1070         return CLI_SUCCESS;
1071 }
1072
1073 /*
1074  * This is testing code for astobj
1075  */
1076 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1077 {
1078         struct ao2_container *c1;
1079         struct ao2_container *c2;
1080         int i, lim;
1081         char *obj;
1082         static int prof_id = -1;
1083         struct ast_cli_args fake_args = { a->fd, 0, NULL };
1084
1085         switch (cmd) {
1086         case CLI_INIT:
1087                 e->command = "astobj2 test";
1088                 e->usage = "Usage: astobj2 test <num>\n"
1089                            "       Runs astobj2 test. Creates 'num' objects,\n"
1090                            "       and test iterators, callbacks and maybe other stuff\n";
1091                 return NULL;
1092         case CLI_GENERATE:
1093                 return NULL;
1094         }
1095
1096         if (a->argc != 3) {
1097                 return CLI_SHOWUSAGE;
1098         }
1099
1100         if (prof_id == -1) {
1101                 prof_id = ast_add_profile("ao2_alloc", 0);
1102         }
1103
1104         ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
1105         lim = atoi(a->argv[2]);
1106         ast_cli(a->fd, "called astobj_test\n");
1107
1108         handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1109         /*
1110          * Allocate a list container.
1111          */
1112         c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
1113                 NULL /* no callback */, "test");
1114         ast_cli(a->fd, "container allocated as %p\n", c1);
1115
1116         /*
1117          * fill the container with objects.
1118          * ao2_alloc() gives us a reference which we pass to the
1119          * container when we do the insert.
1120          */
1121         for (i = 0; i < lim; i++) {
1122                 ast_mark(prof_id, 1 /* start */);
1123                 obj = ao2_t_alloc(80, NULL,"test");
1124                 ast_mark(prof_id, 0 /* stop */);
1125                 ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
1126                 sprintf(obj, "-- this is obj %d --", i);
1127                 ao2_link(c1, obj);
1128                 /* At this point, the refcount on obj is 2 due to the allocation
1129                  * and linking. We can go ahead and reduce the refcount by 1
1130                  * right here so that when the container is unreffed later, the
1131                  * objects will be freed
1132                  */
1133                 ao2_t_ref(obj, -1, "test");
1134         }
1135
1136         ast_cli(a->fd, "testing callbacks\n");
1137         ao2_t_callback(c1, 0, print_cb, a, "test callback");
1138
1139         ast_cli(a->fd, "testing container cloning\n");
1140         c2 = ao2_container_clone(c1, 0);
1141         if (ao2_container_count(c1) != ao2_container_count(c2)) {
1142                 ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
1143         }
1144         ao2_t_callback(c2, 0, print_cb, a, "test callback");
1145
1146         ast_cli(a->fd, "testing iterators, remove every second object\n");
1147         {
1148                 struct ao2_iterator ai;
1149                 int x = 0;
1150
1151                 ai = ao2_iterator_init(c1, 0);
1152                 while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1153                         ast_cli(a->fd, "iterator on <%s>\n", obj);
1154                         if (x++ & 1)
1155                                 ao2_t_unlink(c1, obj,"test");
1156                         ao2_t_ref(obj, -1,"test");
1157                 }
1158                 ao2_iterator_destroy(&ai);
1159                 ast_cli(a->fd, "testing iterators again\n");
1160                 ai = ao2_iterator_init(c1, 0);
1161                 while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1162                         ast_cli(a->fd, "iterator on <%s>\n", obj);
1163                         ao2_t_ref(obj, -1,"test");
1164                 }
1165                 ao2_iterator_destroy(&ai);
1166         }
1167
1168         ast_cli(a->fd, "testing callbacks again\n");
1169         ao2_t_callback(c1, 0, print_cb, a, "test callback");
1170
1171         ast_verbose("now you should see an error and possible assertion failure messages:\n");
1172         ao2_t_ref(&i, -1, "");  /* i is not a valid object so we print an error here */
1173
1174         ast_cli(a->fd, "destroy container\n");
1175         ao2_t_ref(c1, -1, "");  /* destroy container */
1176         ao2_t_ref(c2, -1, "");  /* destroy container */
1177         handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1178         return CLI_SUCCESS;
1179 }
1180 #endif /* AO2_DEBUG */
1181
1182 #if defined(AO2_DEBUG)
1183 static struct ast_cli_entry cli_astobj2[] = {
1184         AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
1185         AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
1186 };
1187 #endif /* AO2_DEBUG */
1188
1189 static void astobj2_cleanup(void)
1190 {
1191 #if defined(AO2_DEBUG)
1192         ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1193 #endif
1194
1195         if (ast_opt_ref_debug) {
1196                 fclose(ref_log);
1197                 ref_log = NULL;
1198         }
1199 }
1200
1201 int astobj2_init(void)
1202 {
1203         char ref_filename[1024];
1204
1205         if (ast_opt_ref_debug) {
1206                 snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
1207                 ref_log = fopen(ref_filename, "w");
1208                 if (!ref_log) {
1209                         ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
1210                 }
1211         }
1212
1213         if (container_init() != 0) {
1214                 fclose(ref_log);
1215                 return -1;
1216         }
1217
1218 #if defined(AO2_DEBUG)
1219         ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1220 #endif  /* defined(AO2_DEBUG) */
1221
1222         ast_register_cleanup(astobj2_cleanup);
1223
1224         return 0;
1225 }