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