f1d5001748bd3635811fb22f3ca19d180d6460f6
[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_FILE_VERSION(__FILE__, "$Revision$")
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         /*! 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 */
61         uint32_t magic;
62 };
63
64 #define AO2_MAGIC       0xa570b123
65
66 /*!
67  * What an astobj2 object looks like: fixed-size private data
68  * followed by variable-size user data.
69  */
70 struct astobj2 {
71         struct __priv_data priv_data;
72         void *user_data[0];
73 };
74
75 struct ao2_lock_priv {
76         ast_mutex_t lock;
77 };
78
79 /* AstObj2 with recursive lock. */
80 struct astobj2_lock {
81         struct ao2_lock_priv mutex;
82         struct __priv_data priv_data;
83         void *user_data[0];
84 };
85
86 struct ao2_rwlock_priv {
87         ast_rwlock_t lock;
88         /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
89         int num_lockers;
90 };
91
92 /* AstObj2 with RW lock. */
93 struct astobj2_rwlock {
94         struct ao2_rwlock_priv rwlock;
95         struct __priv_data priv_data;
96         void *user_data[0];
97 };
98
99 #ifdef AO2_DEBUG
100 struct ao2_stats ao2;
101 #endif
102
103 #define INTERNAL_OBJ_MUTEX(user_data) \
104         ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
105
106 #define INTERNAL_OBJ_RWLOCK(user_data) \
107         ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
108
109 /*!
110  * \brief convert from a pointer _p to a user-defined object
111  *
112  * \return the pointer to the astobj2 structure
113  */
114 static struct astobj2 *INTERNAL_OBJ(void *user_data)
115 {
116         struct astobj2 *p;
117
118         if (!user_data) {
119                 ast_log(LOG_ERROR, "user_data is NULL\n");
120                 return NULL;
121         }
122
123         p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
124         if (AO2_MAGIC != p->priv_data.magic) {
125                 if (p->priv_data.magic) {
126                         ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
127                                 p->priv_data.magic, user_data);
128                 } else {
129                         ast_log(LOG_ERROR,
130                                 "bad magic number for object %p. Object is likely destroyed.\n",
131                                 user_data);
132                 }
133                 ast_assert(0);
134                 return NULL;
135         }
136
137         return p;
138 }
139
140 /*!
141  * \brief convert from a pointer _p to an astobj2 object
142  *
143  * \return the pointer to the user-defined portion.
144  */
145 #define EXTERNAL_OBJ(_p)        ((_p) == NULL ? NULL : (_p)->user_data)
146
147 int is_ao2_object(void *user_data)
148 {
149         return (INTERNAL_OBJ(user_data) != NULL);
150 }
151
152 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
153 {
154         struct astobj2 *obj = INTERNAL_OBJ(user_data);
155         struct astobj2_lock *obj_mutex;
156         struct astobj2_rwlock *obj_rwlock;
157         int res = 0;
158
159         if (obj == NULL) {
160                 ast_assert(0);
161                 return -1;
162         }
163
164         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
165         case AO2_ALLOC_OPT_LOCK_MUTEX:
166                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
167                 res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
168 #ifdef AO2_DEBUG
169                 if (!res) {
170                         ast_atomic_fetchadd_int(&ao2.total_locked, 1);
171                 }
172 #endif
173                 break;
174         case AO2_ALLOC_OPT_LOCK_RWLOCK:
175                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
176                 switch (lock_how) {
177                 case AO2_LOCK_REQ_MUTEX:
178                 case AO2_LOCK_REQ_WRLOCK:
179                         res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
180                         if (!res) {
181                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
182 #ifdef AO2_DEBUG
183                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
184 #endif
185                         }
186                         break;
187                 case AO2_LOCK_REQ_RDLOCK:
188                         res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
189                         if (!res) {
190                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
191 #ifdef AO2_DEBUG
192                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
193 #endif
194                         }
195                         break;
196                 }
197                 break;
198         case AO2_ALLOC_OPT_LOCK_NOLOCK:
199                 /* The ao2 object has no lock. */
200                 break;
201         default:
202                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
203                         user_data);
204                 return -1;
205         }
206
207         return res;
208 }
209
210 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
211 {
212         struct astobj2 *obj = INTERNAL_OBJ(user_data);
213         struct astobj2_lock *obj_mutex;
214         struct astobj2_rwlock *obj_rwlock;
215         int res = 0;
216         int current_value;
217
218         if (obj == NULL) {
219                 ast_assert(0);
220                 return -1;
221         }
222
223         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
224         case AO2_ALLOC_OPT_LOCK_MUTEX:
225                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
226                 res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
227 #ifdef AO2_DEBUG
228                 if (!res) {
229                         ast_atomic_fetchadd_int(&ao2.total_locked, -1);
230                 }
231 #endif
232                 break;
233         case AO2_ALLOC_OPT_LOCK_RWLOCK:
234                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
235
236                 current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
237                 if (current_value < 0) {
238                         /* It was a WRLOCK that we are unlocking.  Fix the count. */
239                         ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
240                 }
241                 res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
242 #ifdef AO2_DEBUG
243                 if (!res) {
244                         ast_atomic_fetchadd_int(&ao2.total_locked, -1);
245                 }
246 #endif
247                 break;
248         case AO2_ALLOC_OPT_LOCK_NOLOCK:
249                 /* The ao2 object has no lock. */
250                 break;
251         default:
252                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
253                         user_data);
254                 res = -1;
255                 break;
256         }
257         return res;
258 }
259
260 int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
261 {
262         struct astobj2 *obj = INTERNAL_OBJ(user_data);
263         struct astobj2_lock *obj_mutex;
264         struct astobj2_rwlock *obj_rwlock;
265         int res = 0;
266
267         if (obj == NULL) {
268                 ast_assert(0);
269                 return -1;
270         }
271
272         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
273         case AO2_ALLOC_OPT_LOCK_MUTEX:
274                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
275                 res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
276 #ifdef AO2_DEBUG
277                 if (!res) {
278                         ast_atomic_fetchadd_int(&ao2.total_locked, 1);
279                 }
280 #endif
281                 break;
282         case AO2_ALLOC_OPT_LOCK_RWLOCK:
283                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
284                 switch (lock_how) {
285                 case AO2_LOCK_REQ_MUTEX:
286                 case AO2_LOCK_REQ_WRLOCK:
287                         res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
288                         if (!res) {
289                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
290 #ifdef AO2_DEBUG
291                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
292 #endif
293                         }
294                         break;
295                 case AO2_LOCK_REQ_RDLOCK:
296                         res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
297                         if (!res) {
298                                 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
299 #ifdef AO2_DEBUG
300                                 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
301 #endif
302                         }
303                         break;
304                 }
305                 break;
306         case AO2_ALLOC_OPT_LOCK_NOLOCK:
307                 /* The ao2 object has no lock. */
308                 return 0;
309         default:
310                 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
311                         user_data);
312                 return -1;
313         }
314
315
316         return res;
317 }
318
319 /*!
320  * \internal
321  * \brief Adjust an object's lock to the requested level.
322  *
323  * \param user_data An ao2 object to adjust lock level.
324  * \param lock_how What level to adjust lock.
325  * \param keep_stronger TRUE if keep original lock level if it is stronger.
326  *
327  * \pre The ao2 object is already locked.
328  *
329  * \details
330  * An ao2 object with a RWLOCK will have its lock level adjusted
331  * to the specified level if it is not already there.  An ao2
332  * object with a different type of lock is not affected.
333  *
334  * \return Original lock level.
335  */
336 enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
337 {
338         struct astobj2 *obj = INTERNAL_OBJ(user_data);
339         struct astobj2_rwlock *obj_rwlock;
340         enum ao2_lock_req orig_lock;
341
342         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
343         case AO2_ALLOC_OPT_LOCK_RWLOCK:
344                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
345                 if (obj_rwlock->rwlock.num_lockers < 0) {
346                         orig_lock = AO2_LOCK_REQ_WRLOCK;
347                 } else {
348                         orig_lock = AO2_LOCK_REQ_RDLOCK;
349                 }
350                 switch (lock_how) {
351                 case AO2_LOCK_REQ_MUTEX:
352                         lock_how = AO2_LOCK_REQ_WRLOCK;
353                         /* Fall through */
354                 case AO2_LOCK_REQ_WRLOCK:
355                         if (lock_how != orig_lock) {
356                                 /* Switch from read lock to write lock. */
357                                 ao2_unlock(user_data);
358                                 ao2_wrlock(user_data);
359                         }
360                         break;
361                 case AO2_LOCK_REQ_RDLOCK:
362                         if (!keep_stronger && lock_how != orig_lock) {
363                                 /* Switch from write lock to read lock. */
364                                 ao2_unlock(user_data);
365                                 ao2_rdlock(user_data);
366                         }
367                         break;
368                 }
369                 break;
370         default:
371                 ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
372                 /* Fall through */
373         case AO2_ALLOC_OPT_LOCK_NOLOCK:
374         case AO2_ALLOC_OPT_LOCK_MUTEX:
375                 orig_lock = AO2_LOCK_REQ_MUTEX;
376                 break;
377         }
378
379         return orig_lock;
380 }
381
382 void *ao2_object_get_lockaddr(void *user_data)
383 {
384         struct astobj2 *obj = INTERNAL_OBJ(user_data);
385         struct astobj2_lock *obj_mutex;
386
387         if (obj == NULL) {
388                 ast_assert(0);
389                 return NULL;
390         }
391
392         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
393         case AO2_ALLOC_OPT_LOCK_MUTEX:
394                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
395                 return &obj_mutex->mutex.lock;
396         default:
397                 break;
398         }
399
400         return NULL;
401 }
402
403 static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func)
404 {
405         struct astobj2 *obj = INTERNAL_OBJ(user_data);
406         struct astobj2_lock *obj_mutex;
407         struct astobj2_rwlock *obj_rwlock;
408         int current_value;
409         int ret;
410
411         if (obj == NULL) {
412                 ast_assert(0);
413                 return -1;
414         }
415
416         /* if delta is 0, just return the refcount */
417         if (delta == 0) {
418                 return obj->priv_data.ref_counter;
419         }
420
421         /* we modify with an atomic operation the reference counter */
422         ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
423         current_value = ret + delta;
424
425 #ifdef AO2_DEBUG
426         ast_atomic_fetchadd_int(&ao2.total_refs, delta);
427 #endif
428
429         if (0 < current_value) {
430                 /* The object still lives. */
431                 return ret;
432         }
433
434         /* this case must never happen */
435         if (current_value < 0) {
436                 ast_log(__LOG_ERROR, file, line, func,
437                         "Invalid refcount %d on ao2 object %p\n", current_value, user_data);
438                 ast_assert(0);
439                 /* stop here even if assert doesn't DO_CRASH */
440                 return -1;
441         }
442
443         /* last reference, destroy the object */
444         if (obj->priv_data.destructor_fn != NULL) {
445                 obj->priv_data.destructor_fn(user_data);
446         }
447
448 #ifdef AO2_DEBUG
449         ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
450         ast_atomic_fetchadd_int(&ao2.total_objects, -1);
451 #endif
452
453         /* In case someone uses an object after it's been freed */
454         obj->priv_data.magic = 0;
455
456         switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
457         case AO2_ALLOC_OPT_LOCK_MUTEX:
458                 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
459                 ast_mutex_destroy(&obj_mutex->mutex.lock);
460
461                 ast_free(obj_mutex);
462                 break;
463         case AO2_ALLOC_OPT_LOCK_RWLOCK:
464                 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
465                 ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
466
467                 ast_free(obj_rwlock);
468                 break;
469         case AO2_ALLOC_OPT_LOCK_NOLOCK:
470                 ast_free(obj);
471                 break;
472         default:
473                 ast_log(__LOG_ERROR, file, line, func,
474                         "Invalid lock option on ao2 object %p\n", user_data);
475                 break;
476         }
477
478         return ret;
479 }
480
481 int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
482 {
483         struct astobj2 *obj = INTERNAL_OBJ(user_data);
484         int old_refcount = -1;
485
486         if (obj) {
487                 old_refcount = internal_ao2_ref(user_data, delta, file, line, func);
488         }
489
490         if (ref_log && user_data) {
491                 if (!obj) {
492                         /* Invalid object: Bad magic number. */
493                         fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
494                                 user_data, delta, ast_get_tid(), file, line, func, tag);
495                         fflush(ref_log);
496                 } else if (old_refcount + delta == 0) {
497                         fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
498                                 user_data, delta, ast_get_tid(), file, line, func, tag);
499                         fflush(ref_log);
500                 } else if (delta != 0) {
501                         fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"),
502                                 delta, ast_get_tid(), file, line, func, old_refcount, tag);
503                         fflush(ref_log);
504                 }
505         }
506
507         if (obj == NULL) {
508                 ast_assert(0);
509         }
510
511         return old_refcount;
512 }
513
514 int __ao2_ref(void *user_data, int delta)
515 {
516         return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
517 }
518
519 void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
520 {
521         if (obj) {
522                 __ao2_ref_debug(obj, -1, tag, file, line, function);
523         }
524 }
525
526 void __ao2_cleanup(void *obj)
527 {
528         if (obj) {
529                 ao2_ref(obj, -1);
530         }
531 }
532
533 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func)
534 {
535         /* allocation */
536         struct astobj2 *obj;
537         struct astobj2_lock *obj_mutex;
538         struct astobj2_rwlock *obj_rwlock;
539
540         switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
541         case AO2_ALLOC_OPT_LOCK_MUTEX:
542 #if defined(__AST_DEBUG_MALLOC)
543                 obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func);
544 #else
545                 obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size);
546 #endif
547                 if (obj_mutex == NULL) {
548                         return NULL;
549                 }
550
551                 ast_mutex_init(&obj_mutex->mutex.lock);
552                 obj = (struct astobj2 *) &obj_mutex->priv_data;
553                 break;
554         case AO2_ALLOC_OPT_LOCK_RWLOCK:
555 #if defined(__AST_DEBUG_MALLOC)
556                 obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func);
557 #else
558                 obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size);
559 #endif
560                 if (obj_rwlock == NULL) {
561                         return NULL;
562                 }
563
564                 ast_rwlock_init(&obj_rwlock->rwlock.lock);
565                 obj = (struct astobj2 *) &obj_rwlock->priv_data;
566                 break;
567         case AO2_ALLOC_OPT_LOCK_NOLOCK:
568 #if defined(__AST_DEBUG_MALLOC)
569                 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func);
570 #else
571                 obj = ast_calloc(1, sizeof(*obj) + data_size);
572 #endif
573                 if (obj == NULL) {
574                         return NULL;
575                 }
576                 break;
577         default:
578                 /* Invalid option value. */
579                 ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
580                 return NULL;
581         }
582
583         /* Initialize common ao2 values. */
584         obj->priv_data.ref_counter = 1;
585         obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
586         obj->priv_data.data_size = data_size;
587         obj->priv_data.options = options;
588         obj->priv_data.magic = AO2_MAGIC;
589
590 #ifdef AO2_DEBUG
591         ast_atomic_fetchadd_int(&ao2.total_objects, 1);
592         ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
593         ast_atomic_fetchadd_int(&ao2.total_refs, 1);
594 #endif
595
596         /* return a pointer to the user data */
597         return EXTERNAL_OBJ(obj);
598 }
599
600 unsigned int ao2_options_get(void *obj)
601 {
602         struct astobj2 *orig_obj = INTERNAL_OBJ(obj);
603         if (!orig_obj) {
604                 return 0;
605         }
606         return orig_obj->priv_data.options;
607 }
608
609 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
610         const char *file, int line, const char *func, int ref_debug)
611 {
612         /* allocation */
613         void *obj;
614
615         if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, func)) == NULL) {
616                 return NULL;
617         }
618
619         if (ref_log) {
620                 fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj, ast_get_tid(), file, line, func, tag);
621                 fflush(ref_log);
622         }
623
624         /* return a pointer to the user data */
625         return obj;
626 }
627
628 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options)
629 {
630         return internal_ao2_alloc(data_size, destructor_fn, options, __FILE__, __LINE__, __FUNCTION__);
631 }
632
633
634 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
635 {
636         if (!holder) {
637                 /* For sanity */
638                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
639                 ast_assert(0);
640                 return;
641         }
642         if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
643                 /* Could not get the write lock. */
644                 ast_assert(0);
645                 return;
646         }
647
648         /* Release the held ao2 object. */
649         if (holder->obj) {
650                 if (tag) {
651                         __ao2_ref_debug(holder->obj, -1, tag, file, line, func);
652                 } else {
653                         __ao2_ref(holder->obj, -1);
654                 }
655                 holder->obj = NULL;
656         }
657
658         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
659 }
660
661 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)
662 {
663         void *obj_old;
664
665         if (!holder) {
666                 /* For sanity */
667                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
668                 ast_assert(0);
669                 return NULL;
670         }
671         if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
672                 /* Could not get the write lock. */
673                 ast_assert(0);
674                 return NULL;
675         }
676
677         if (obj) {
678                 if (tag) {
679                         __ao2_ref_debug(obj, +1, tag, file, line, func);
680                 } else {
681                         __ao2_ref(obj, +1);
682                 }
683         }
684         obj_old = holder->obj;
685         holder->obj = obj;
686
687         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
688
689         return obj_old;
690 }
691
692 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)
693 {
694         void *obj_old;
695
696         obj_old = __ao2_global_obj_replace(holder, obj, tag, file, line, func, name);
697         if (obj_old) {
698                 if (tag) {
699                         __ao2_ref_debug(obj_old, -1, tag, file, line, func);
700                 } else {
701                         __ao2_ref(obj_old, -1);
702                 }
703                 return 1;
704         }
705         return 0;
706 }
707
708 void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
709 {
710         void *obj;
711
712         if (!holder) {
713                 /* For sanity */
714                 ast_log(LOG_ERROR, "Must be called with a global object!\n");
715                 ast_assert(0);
716                 return NULL;
717         }
718
719         if (__ast_rwlock_rdlock(file, line, func, &holder->lock, name)) {
720                 /* Could not get the read lock. */
721                 ast_assert(0);
722                 return NULL;
723         }
724
725         obj = holder->obj;
726         if (obj) {
727                 if (tag) {
728                         __ao2_ref_debug(obj, +1, tag, file, line, func);
729                 } else {
730                         __ao2_ref(obj, +1);
731                 }
732         }
733
734         __ast_rwlock_unlock(file, line, func, &holder->lock, name);
735
736         return obj;
737 }
738
739 #ifdef AO2_DEBUG
740 static int print_cb(void *obj, void *arg, int flag)
741 {
742         struct ast_cli_args *a = (struct ast_cli_args *) arg;
743         char *s = (char *)obj;
744
745         ast_cli(a->fd, "string <%s>\n", s);
746         return 0;
747 }
748
749 /*
750  * Print stats
751  */
752 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
753 {
754         switch (cmd) {
755         case CLI_INIT:
756                 e->command = "astobj2 show stats";
757                 e->usage = "Usage: astobj2 show stats\n"
758                            "       Show astobj2 show stats\n";
759                 return NULL;
760         case CLI_GENERATE:
761                 return NULL;
762         }
763         ast_cli(a->fd, "Objects    : %d\n", ao2.total_objects);
764         ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
765         ast_cli(a->fd, "Memory     : %d\n", ao2.total_mem);
766         ast_cli(a->fd, "Locked     : %d\n", ao2.total_locked);
767         ast_cli(a->fd, "Refs       : %d\n", ao2.total_refs);
768         return CLI_SUCCESS;
769 }
770
771 /*
772  * This is testing code for astobj
773  */
774 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
775 {
776         struct ao2_container *c1;
777         struct ao2_container *c2;
778         int i, lim;
779         char *obj;
780         static int prof_id = -1;
781         struct ast_cli_args fake_args = { a->fd, 0, NULL };
782
783         switch (cmd) {
784         case CLI_INIT:
785                 e->command = "astobj2 test";
786                 e->usage = "Usage: astobj2 test <num>\n"
787                            "       Runs astobj2 test. Creates 'num' objects,\n"
788                            "       and test iterators, callbacks and maybe other stuff\n";
789                 return NULL;
790         case CLI_GENERATE:
791                 return NULL;
792         }
793
794         if (a->argc != 3) {
795                 return CLI_SHOWUSAGE;
796         }
797
798         if (prof_id == -1) {
799                 prof_id = ast_add_profile("ao2_alloc", 0);
800         }
801
802         ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
803         lim = atoi(a->argv[2]);
804         ast_cli(a->fd, "called astobj_test\n");
805
806         handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
807         /*
808          * Allocate a list container.
809          */
810         c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
811                 NULL /* no callback */, "test");
812         ast_cli(a->fd, "container allocated as %p\n", c1);
813
814         /*
815          * fill the container with objects.
816          * ao2_alloc() gives us a reference which we pass to the
817          * container when we do the insert.
818          */
819         for (i = 0; i < lim; i++) {
820                 ast_mark(prof_id, 1 /* start */);
821                 obj = ao2_t_alloc(80, NULL,"test");
822                 ast_mark(prof_id, 0 /* stop */);
823                 ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
824                 sprintf(obj, "-- this is obj %d --", i);
825                 ao2_link(c1, obj);
826                 /* At this point, the refcount on obj is 2 due to the allocation
827                  * and linking. We can go ahead and reduce the refcount by 1
828                  * right here so that when the container is unreffed later, the
829                  * objects will be freed
830                  */
831                 ao2_t_ref(obj, -1, "test");
832         }
833
834         ast_cli(a->fd, "testing callbacks\n");
835         ao2_t_callback(c1, 0, print_cb, a, "test callback");
836
837         ast_cli(a->fd, "testing container cloning\n");
838         c2 = ao2_container_clone(c1, 0);
839         if (ao2_container_count(c1) != ao2_container_count(c2)) {
840                 ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
841         }
842         ao2_t_callback(c2, 0, print_cb, a, "test callback");
843
844         ast_cli(a->fd, "testing iterators, remove every second object\n");
845         {
846                 struct ao2_iterator ai;
847                 int x = 0;
848
849                 ai = ao2_iterator_init(c1, 0);
850                 while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
851                         ast_cli(a->fd, "iterator on <%s>\n", obj);
852                         if (x++ & 1)
853                                 ao2_t_unlink(c1, obj,"test");
854                         ao2_t_ref(obj, -1,"test");
855                 }
856                 ao2_iterator_destroy(&ai);
857                 ast_cli(a->fd, "testing iterators again\n");
858                 ai = ao2_iterator_init(c1, 0);
859                 while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
860                         ast_cli(a->fd, "iterator on <%s>\n", obj);
861                         ao2_t_ref(obj, -1,"test");
862                 }
863                 ao2_iterator_destroy(&ai);
864         }
865
866         ast_cli(a->fd, "testing callbacks again\n");
867         ao2_t_callback(c1, 0, print_cb, a, "test callback");
868
869         ast_verbose("now you should see an error and possible assertion failure messages:\n");
870         ao2_t_ref(&i, -1, "");  /* i is not a valid object so we print an error here */
871
872         ast_cli(a->fd, "destroy container\n");
873         ao2_t_ref(c1, -1, "");  /* destroy container */
874         ao2_t_ref(c2, -1, "");  /* destroy container */
875         handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
876         return CLI_SUCCESS;
877 }
878 #endif /* AO2_DEBUG */
879
880 #if defined(AO2_DEBUG)
881 static struct ast_cli_entry cli_astobj2[] = {
882         AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
883         AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
884 };
885 #endif /* AO2_DEBUG */
886
887 static void astobj2_cleanup(void)
888 {
889 #if defined(AO2_DEBUG)
890         ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
891 #endif
892 #ifdef REF_DEBUG
893         fclose(ref_log);
894         ref_log = NULL;
895 #endif
896 }
897
898 int astobj2_init(void)
899 {
900 #ifdef REF_DEBUG
901         char ref_filename[1024];
902 #endif
903
904         if (container_init() != 0) {
905                 return -1;
906         }
907
908 #ifdef REF_DEBUG
909         snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
910         ref_log = fopen(ref_filename, "w");
911         if (!ref_log) {
912                 ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
913         }
914 #endif
915
916 #if defined(AO2_DEBUG)
917         ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
918 #endif  /* defined(AO2_DEBUG) */
919
920         ast_register_cleanup(astobj2_cleanup);
921
922         return 0;
923 }