astobj2.c

Go to the documentation of this file.
00001 /*
00002  * astobj2 - replacement containers for asterisk data structures.
00003  *
00004  * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
00005  *
00006  * See http://www.asterisk.org for more information about
00007  * the Asterisk project. Please do not directly contact
00008  * any of the maintainers of this project for assistance;
00009  * the project provides a web site, mailing lists and IRC
00010  * channels for your use.
00011  *
00012  * This program is free software, distributed under the terms of
00013  * the GNU General Public License Version 2. See the LICENSE file
00014  * at the top of the source tree.
00015  */
00016 
00017 /*! \file
00018  *
00019  * \brief Functions implementing astobj2 objects.
00020  *
00021  * \author Richard Mudgett <rmudgett@digium.com>
00022  */
00023 
00024 /*** MODULEINFO
00025    <support_level>core</support_level>
00026  ***/
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433524 $")
00031 
00032 #include "asterisk/_private.h"
00033 #include "asterisk/astobj2.h"
00034 #include "astobj2_private.h"
00035 #include "astobj2_container_private.h"
00036 #include "asterisk/cli.h"
00037 #include "asterisk/paths.h"
00038 
00039 /* Use ast_log_safe in place of ast_log. */
00040 #define ast_log ast_log_safe
00041 
00042 static FILE *ref_log;
00043 
00044 /*!
00045  * astobj2 objects are always preceded by this data structure,
00046  * which contains a reference counter,
00047  * option flags and a pointer to a destructor.
00048  * The refcount is used to decide when it is time to
00049  * invoke the destructor.
00050  * The magic number is used for consistency check.
00051  */
00052 struct __priv_data {
00053    int ref_counter;
00054    ao2_destructor_fn destructor_fn;
00055    /*! User data size for stats */
00056    size_t data_size;
00057    /*! The ao2 object option flags */
00058    uint32_t options;
00059    /*! magic number.  This is used to verify that a pointer passed in is a
00060     *  valid astobj2 */
00061    uint32_t magic;
00062 };
00063 
00064 #define  AO2_MAGIC   0xa570b123
00065 
00066 /*!
00067  * What an astobj2 object looks like: fixed-size private data
00068  * followed by variable-size user data.
00069  */
00070 struct astobj2 {
00071    struct __priv_data priv_data;
00072    void *user_data[0];
00073 };
00074 
00075 struct ao2_lock_priv {
00076    ast_mutex_t lock;
00077 };
00078 
00079 /* AstObj2 with recursive lock. */
00080 struct astobj2_lock {
00081    struct ao2_lock_priv mutex;
00082    struct __priv_data priv_data;
00083    void *user_data[0];
00084 };
00085 
00086 struct ao2_rwlock_priv {
00087    ast_rwlock_t lock;
00088    /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
00089    int num_lockers;
00090 };
00091 
00092 /* AstObj2 with RW lock. */
00093 struct astobj2_rwlock {
00094    struct ao2_rwlock_priv rwlock;
00095    struct __priv_data priv_data;
00096    void *user_data[0];
00097 };
00098 
00099 #ifdef AO2_DEBUG
00100 struct ao2_stats ao2;
00101 #endif
00102 
00103 #define INTERNAL_OBJ_MUTEX(user_data) \
00104    ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
00105 
00106 #define INTERNAL_OBJ_RWLOCK(user_data) \
00107    ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
00108 
00109 /*!
00110  * \brief convert from a pointer _p to a user-defined object
00111  *
00112  * \return the pointer to the astobj2 structure
00113  */
00114 static struct astobj2 *INTERNAL_OBJ(void *user_data)
00115 {
00116    struct astobj2 *p;
00117 
00118    if (!user_data) {
00119       ast_log(LOG_ERROR, "user_data is NULL\n");
00120       return NULL;
00121    }
00122 
00123    p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
00124    if (AO2_MAGIC != p->priv_data.magic) {
00125       if (p->priv_data.magic) {
00126          ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
00127             p->priv_data.magic, user_data);
00128       } else {
00129          ast_log(LOG_ERROR,
00130             "bad magic number for object %p. Object is likely destroyed.\n",
00131             user_data);
00132       }
00133       ast_assert(0);
00134       return NULL;
00135    }
00136 
00137    return p;
00138 }
00139 
00140 /*!
00141  * \brief convert from a pointer _p to an astobj2 object
00142  *
00143  * \return the pointer to the user-defined portion.
00144  */
00145 #define EXTERNAL_OBJ(_p)   ((_p) == NULL ? NULL : (_p)->user_data)
00146 
00147 int is_ao2_object(void *user_data)
00148 {
00149    return (INTERNAL_OBJ(user_data) != NULL);
00150 }
00151 
00152 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
00153 {
00154    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00155    struct astobj2_lock *obj_mutex;
00156    struct astobj2_rwlock *obj_rwlock;
00157    int res = 0;
00158 
00159    if (obj == NULL) {
00160       ast_assert(0);
00161       return -1;
00162    }
00163 
00164    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00165    case AO2_ALLOC_OPT_LOCK_MUTEX:
00166       obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
00167       res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
00168 #ifdef AO2_DEBUG
00169       if (!res) {
00170          ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00171       }
00172 #endif
00173       break;
00174    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00175       obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
00176       switch (lock_how) {
00177       case AO2_LOCK_REQ_MUTEX:
00178       case AO2_LOCK_REQ_WRLOCK:
00179          res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
00180          if (!res) {
00181             ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
00182 #ifdef AO2_DEBUG
00183             ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00184 #endif
00185          }
00186          break;
00187       case AO2_LOCK_REQ_RDLOCK:
00188          res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
00189          if (!res) {
00190             ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
00191 #ifdef AO2_DEBUG
00192             ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00193 #endif
00194          }
00195          break;
00196       }
00197       break;
00198    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00199       /* The ao2 object has no lock. */
00200       break;
00201    default:
00202       ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
00203          user_data);
00204       return -1;
00205    }
00206 
00207    return res;
00208 }
00209 
00210 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
00211 {
00212    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00213    struct astobj2_lock *obj_mutex;
00214    struct astobj2_rwlock *obj_rwlock;
00215    int res = 0;
00216    int current_value;
00217 
00218    if (obj == NULL) {
00219       ast_assert(0);
00220       return -1;
00221    }
00222 
00223    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00224    case AO2_ALLOC_OPT_LOCK_MUTEX:
00225       obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
00226       res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
00227 #ifdef AO2_DEBUG
00228       if (!res) {
00229          ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00230       }
00231 #endif
00232       break;
00233    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00234       obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
00235 
00236       current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
00237       if (current_value < 0) {
00238          /* It was a WRLOCK that we are unlocking.  Fix the count. */
00239          ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
00240       }
00241       res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
00242 #ifdef AO2_DEBUG
00243       if (!res) {
00244          ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00245       }
00246 #endif
00247       break;
00248    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00249       /* The ao2 object has no lock. */
00250       break;
00251    default:
00252       ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
00253          user_data);
00254       res = -1;
00255       break;
00256    }
00257    return res;
00258 }
00259 
00260 int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
00261 {
00262    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00263    struct astobj2_lock *obj_mutex;
00264    struct astobj2_rwlock *obj_rwlock;
00265    int res = 0;
00266 
00267    if (obj == NULL) {
00268       ast_assert(0);
00269       return -1;
00270    }
00271 
00272    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00273    case AO2_ALLOC_OPT_LOCK_MUTEX:
00274       obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
00275       res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
00276 #ifdef AO2_DEBUG
00277       if (!res) {
00278          ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00279       }
00280 #endif
00281       break;
00282    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00283       obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
00284       switch (lock_how) {
00285       case AO2_LOCK_REQ_MUTEX:
00286       case AO2_LOCK_REQ_WRLOCK:
00287          res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
00288          if (!res) {
00289             ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
00290 #ifdef AO2_DEBUG
00291             ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00292 #endif
00293          }
00294          break;
00295       case AO2_LOCK_REQ_RDLOCK:
00296          res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
00297          if (!res) {
00298             ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
00299 #ifdef AO2_DEBUG
00300             ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00301 #endif
00302          }
00303          break;
00304       }
00305       break;
00306    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00307       /* The ao2 object has no lock. */
00308       return 0;
00309    default:
00310       ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
00311          user_data);
00312       return -1;
00313    }
00314 
00315 
00316    return res;
00317 }
00318 
00319 /*!
00320  * \internal
00321  * \brief Adjust an object's lock to the requested level.
00322  *
00323  * \param user_data An ao2 object to adjust lock level.
00324  * \param lock_how What level to adjust lock.
00325  * \param keep_stronger TRUE if keep original lock level if it is stronger.
00326  *
00327  * \pre The ao2 object is already locked.
00328  *
00329  * \details
00330  * An ao2 object with a RWLOCK will have its lock level adjusted
00331  * to the specified level if it is not already there.  An ao2
00332  * object with a different type of lock is not affected.
00333  *
00334  * \return Original lock level.
00335  */
00336 enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
00337 {
00338    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00339    struct astobj2_rwlock *obj_rwlock;
00340    enum ao2_lock_req orig_lock;
00341 
00342    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00343    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00344       obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
00345       if (obj_rwlock->rwlock.num_lockers < 0) {
00346          orig_lock = AO2_LOCK_REQ_WRLOCK;
00347       } else {
00348          orig_lock = AO2_LOCK_REQ_RDLOCK;
00349       }
00350       switch (lock_how) {
00351       case AO2_LOCK_REQ_MUTEX:
00352          lock_how = AO2_LOCK_REQ_WRLOCK;
00353          /* Fall through */
00354       case AO2_LOCK_REQ_WRLOCK:
00355          if (lock_how != orig_lock) {
00356             /* Switch from read lock to write lock. */
00357             ao2_unlock(user_data);
00358             ao2_wrlock(user_data);
00359          }
00360          break;
00361       case AO2_LOCK_REQ_RDLOCK:
00362          if (!keep_stronger && lock_how != orig_lock) {
00363             /* Switch from write lock to read lock. */
00364             ao2_unlock(user_data);
00365             ao2_rdlock(user_data);
00366          }
00367          break;
00368       }
00369       break;
00370    default:
00371       ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
00372       /* Fall through */
00373    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00374    case AO2_ALLOC_OPT_LOCK_MUTEX:
00375       orig_lock = AO2_LOCK_REQ_MUTEX;
00376       break;
00377    }
00378 
00379    return orig_lock;
00380 }
00381 
00382 void *ao2_object_get_lockaddr(void *user_data)
00383 {
00384    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00385    struct astobj2_lock *obj_mutex;
00386 
00387    if (obj == NULL) {
00388       ast_assert(0);
00389       return NULL;
00390    }
00391 
00392    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00393    case AO2_ALLOC_OPT_LOCK_MUTEX:
00394       obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
00395       return &obj_mutex->mutex.lock;
00396    default:
00397       break;
00398    }
00399 
00400    return NULL;
00401 }
00402 
00403 static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func)
00404 {
00405    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00406    struct astobj2_lock *obj_mutex;
00407    struct astobj2_rwlock *obj_rwlock;
00408    int current_value;
00409    int ret;
00410 
00411    if (obj == NULL) {
00412       ast_assert(0);
00413       return -1;
00414    }
00415 
00416    /* if delta is 0, just return the refcount */
00417    if (delta == 0) {
00418       return obj->priv_data.ref_counter;
00419    }
00420 
00421    /* we modify with an atomic operation the reference counter */
00422    ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
00423    current_value = ret + delta;
00424 
00425 #ifdef AO2_DEBUG
00426    ast_atomic_fetchadd_int(&ao2.total_refs, delta);
00427 #endif
00428 
00429    if (0 < current_value) {
00430       /* The object still lives. */
00431       return ret;
00432    }
00433 
00434    /* this case must never happen */
00435    if (current_value < 0) {
00436       ast_log(__LOG_ERROR, file, line, func,
00437          "Invalid refcount %d on ao2 object %p\n", current_value, user_data);
00438       ast_assert(0);
00439       /* stop here even if assert doesn't DO_CRASH */
00440       return -1;
00441    }
00442 
00443    /* last reference, destroy the object */
00444    if (obj->priv_data.destructor_fn != NULL) {
00445       obj->priv_data.destructor_fn(user_data);
00446    }
00447 
00448 #ifdef AO2_DEBUG
00449    ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
00450    ast_atomic_fetchadd_int(&ao2.total_objects, -1);
00451 #endif
00452 
00453    /* In case someone uses an object after it's been freed */
00454    obj->priv_data.magic = 0;
00455 
00456    switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
00457    case AO2_ALLOC_OPT_LOCK_MUTEX:
00458       obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
00459       ast_mutex_destroy(&obj_mutex->mutex.lock);
00460 
00461       ast_free(obj_mutex);
00462       break;
00463    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00464       obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
00465       ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
00466 
00467       ast_free(obj_rwlock);
00468       break;
00469    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00470       ast_free(obj);
00471       break;
00472    default:
00473       ast_log(__LOG_ERROR, file, line, func,
00474          "Invalid lock option on ao2 object %p\n", user_data);
00475       break;
00476    }
00477 
00478    return ret;
00479 }
00480 
00481 int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
00482 {
00483    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00484    int old_refcount = -1;
00485 
00486    if (obj) {
00487       old_refcount = internal_ao2_ref(user_data, delta, file, line, func);
00488    }
00489 
00490    if (ref_log && user_data) {
00491       if (!obj) {
00492          /* Invalid object: Bad magic number. */
00493          fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
00494             user_data, delta, ast_get_tid(), file, line, func, tag);
00495          fflush(ref_log);
00496       } else if (old_refcount + delta == 0) {
00497          fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
00498             user_data, delta, ast_get_tid(), file, line, func, tag);
00499          fflush(ref_log);
00500       } else if (delta != 0) {
00501          fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"),
00502             delta, ast_get_tid(), file, line, func, old_refcount, tag);
00503          fflush(ref_log);
00504       }
00505    }
00506 
00507    if (obj == NULL) {
00508       ast_assert(0);
00509    }
00510 
00511    return old_refcount;
00512 }
00513 
00514 int __ao2_ref(void *user_data, int delta)
00515 {
00516    return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
00517 }
00518 
00519 void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
00520 {
00521    if (obj) {
00522       __ao2_ref_debug(obj, -1, tag, file, line, function);
00523    }
00524 }
00525 
00526 void __ao2_cleanup(void *obj)
00527 {
00528    if (obj) {
00529       ao2_ref(obj, -1);
00530    }
00531 }
00532 
00533 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)
00534 {
00535    /* allocation */
00536    struct astobj2 *obj;
00537    struct astobj2_lock *obj_mutex;
00538    struct astobj2_rwlock *obj_rwlock;
00539 
00540    switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
00541    case AO2_ALLOC_OPT_LOCK_MUTEX:
00542 #if defined(__AST_DEBUG_MALLOC)
00543       obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func);
00544 #else
00545       obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size);
00546 #endif
00547       if (obj_mutex == NULL) {
00548          return NULL;
00549       }
00550 
00551       ast_mutex_init(&obj_mutex->mutex.lock);
00552       obj = (struct astobj2 *) &obj_mutex->priv_data;
00553       break;
00554    case AO2_ALLOC_OPT_LOCK_RWLOCK:
00555 #if defined(__AST_DEBUG_MALLOC)
00556       obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func);
00557 #else
00558       obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size);
00559 #endif
00560       if (obj_rwlock == NULL) {
00561          return NULL;
00562       }
00563 
00564       ast_rwlock_init(&obj_rwlock->rwlock.lock);
00565       obj = (struct astobj2 *) &obj_rwlock->priv_data;
00566       break;
00567    case AO2_ALLOC_OPT_LOCK_NOLOCK:
00568 #if defined(__AST_DEBUG_MALLOC)
00569       obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func);
00570 #else
00571       obj = ast_calloc(1, sizeof(*obj) + data_size);
00572 #endif
00573       if (obj == NULL) {
00574          return NULL;
00575       }
00576       break;
00577    default:
00578       /* Invalid option value. */
00579       ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
00580       return NULL;
00581    }
00582 
00583    /* Initialize common ao2 values. */
00584    obj->priv_data.ref_counter = 1;
00585    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00586    obj->priv_data.data_size = data_size;
00587    obj->priv_data.options = options;
00588    obj->priv_data.magic = AO2_MAGIC;
00589 
00590 #ifdef AO2_DEBUG
00591    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00592    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00593    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00594 #endif
00595 
00596    /* return a pointer to the user data */
00597    return EXTERNAL_OBJ(obj);
00598 }
00599 
00600 unsigned int ao2_options_get(void *obj)
00601 {
00602    struct astobj2 *orig_obj = INTERNAL_OBJ(obj);
00603    if (!orig_obj) {
00604       return 0;
00605    }
00606    return orig_obj->priv_data.options;
00607 }
00608 
00609 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
00610    const char *file, int line, const char *func, int ref_debug)
00611 {
00612    /* allocation */
00613    void *obj;
00614 
00615    if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, func)) == NULL) {
00616       return NULL;
00617    }
00618 
00619    if (ref_log) {
00620       fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj, ast_get_tid(), file, line, func, tag);
00621       fflush(ref_log);
00622    }
00623 
00624    /* return a pointer to the user data */
00625    return obj;
00626 }
00627 
00628 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options)
00629 {
00630    return internal_ao2_alloc(data_size, destructor_fn, options, __FILE__, __LINE__, __FUNCTION__);
00631 }
00632 
00633 
00634 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
00635 {
00636    if (!holder) {
00637       /* For sanity */
00638       ast_log(LOG_ERROR, "Must be called with a global object!\n");
00639       ast_assert(0);
00640       return;
00641    }
00642    if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
00643       /* Could not get the write lock. */
00644       ast_assert(0);
00645       return;
00646    }
00647 
00648    /* Release the held ao2 object. */
00649    if (holder->obj) {
00650       if (tag) {
00651          __ao2_ref_debug(holder->obj, -1, tag, file, line, func);
00652       } else {
00653          __ao2_ref(holder->obj, -1);
00654       }
00655       holder->obj = NULL;
00656    }
00657 
00658    __ast_rwlock_unlock(file, line, func, &holder->lock, name);
00659 }
00660 
00661 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)
00662 {
00663    void *obj_old;
00664 
00665    if (!holder) {
00666       /* For sanity */
00667       ast_log(LOG_ERROR, "Must be called with a global object!\n");
00668       ast_assert(0);
00669       return NULL;
00670    }
00671    if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
00672       /* Could not get the write lock. */
00673       ast_assert(0);
00674       return NULL;
00675    }
00676 
00677    if (obj) {
00678       if (tag) {
00679          __ao2_ref_debug(obj, +1, tag, file, line, func);
00680       } else {
00681          __ao2_ref(obj, +1);
00682       }
00683    }
00684    obj_old = holder->obj;
00685    holder->obj = obj;
00686 
00687    __ast_rwlock_unlock(file, line, func, &holder->lock, name);
00688 
00689    return obj_old;
00690 }
00691 
00692 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)
00693 {
00694    void *obj_old;
00695 
00696    obj_old = __ao2_global_obj_replace(holder, obj, tag, file, line, func, name);
00697    if (obj_old) {
00698       if (tag) {
00699          __ao2_ref_debug(obj_old, -1, tag, file, line, func);
00700       } else {
00701          __ao2_ref(obj_old, -1);
00702       }
00703       return 1;
00704    }
00705    return 0;
00706 }
00707 
00708 void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
00709 {
00710    void *obj;
00711 
00712    if (!holder) {
00713       /* For sanity */
00714       ast_log(LOG_ERROR, "Must be called with a global object!\n");
00715       ast_assert(0);
00716       return NULL;
00717    }
00718 
00719    if (__ast_rwlock_rdlock(file, line, func, &holder->lock, name)) {
00720       /* Could not get the read lock. */
00721       ast_assert(0);
00722       return NULL;
00723    }
00724 
00725    obj = holder->obj;
00726    if (obj) {
00727       if (tag) {
00728          __ao2_ref_debug(obj, +1, tag, file, line, func);
00729       } else {
00730          __ao2_ref(obj, +1);
00731       }
00732    }
00733 
00734    __ast_rwlock_unlock(file, line, func, &holder->lock, name);
00735 
00736    return obj;
00737 }
00738 
00739 #ifdef AO2_DEBUG
00740 static int print_cb(void *obj, void *arg, int flag)
00741 {
00742    struct ast_cli_args *a = (struct ast_cli_args *) arg;
00743    char *s = (char *)obj;
00744 
00745    ast_cli(a->fd, "string <%s>\n", s);
00746    return 0;
00747 }
00748 
00749 /*
00750  * Print stats
00751  */
00752 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00753 {
00754    switch (cmd) {
00755    case CLI_INIT:
00756       e->command = "astobj2 show stats";
00757       e->usage = "Usage: astobj2 show stats\n"
00758             "       Show astobj2 show stats\n";
00759       return NULL;
00760    case CLI_GENERATE:
00761       return NULL;
00762    }
00763    ast_cli(a->fd, "Objects    : %d\n", ao2.total_objects);
00764    ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
00765    ast_cli(a->fd, "Memory     : %d\n", ao2.total_mem);
00766    ast_cli(a->fd, "Locked     : %d\n", ao2.total_locked);
00767    ast_cli(a->fd, "Refs       : %d\n", ao2.total_refs);
00768    return CLI_SUCCESS;
00769 }
00770 
00771 /*
00772  * This is testing code for astobj
00773  */
00774 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00775 {
00776    struct ao2_container *c1;
00777    struct ao2_container *c2;
00778    int i, lim;
00779    char *obj;
00780    static int prof_id = -1;
00781    struct ast_cli_args fake_args = { a->fd, 0, NULL };
00782 
00783    switch (cmd) {
00784    case CLI_INIT:
00785       e->command = "astobj2 test";
00786       e->usage = "Usage: astobj2 test <num>\n"
00787             "       Runs astobj2 test. Creates 'num' objects,\n"
00788             "       and test iterators, callbacks and maybe other stuff\n";
00789       return NULL;
00790    case CLI_GENERATE:
00791       return NULL;
00792    }
00793 
00794    if (a->argc != 3) {
00795       return CLI_SHOWUSAGE;
00796    }
00797 
00798    if (prof_id == -1) {
00799       prof_id = ast_add_profile("ao2_alloc", 0);
00800    }
00801 
00802    ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
00803    lim = atoi(a->argv[2]);
00804    ast_cli(a->fd, "called astobj_test\n");
00805 
00806    handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
00807    /*
00808     * Allocate a list container.
00809     */
00810    c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */,
00811       NULL /* no callback */, "test");
00812    ast_cli(a->fd, "container allocated as %p\n", c1);
00813 
00814    /*
00815     * fill the container with objects.
00816     * ao2_alloc() gives us a reference which we pass to the
00817     * container when we do the insert.
00818     */
00819    for (i = 0; i < lim; i++) {
00820       ast_mark(prof_id, 1 /* start */);
00821       obj = ao2_t_alloc(80, NULL,"test");
00822       ast_mark(prof_id, 0 /* stop */);
00823       ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
00824       sprintf(obj, "-- this is obj %d --", i);
00825       ao2_link(c1, obj);
00826       /* At this point, the refcount on obj is 2 due to the allocation
00827        * and linking. We can go ahead and reduce the refcount by 1
00828        * right here so that when the container is unreffed later, the
00829        * objects will be freed
00830        */
00831       ao2_t_ref(obj, -1, "test");
00832    }
00833 
00834    ast_cli(a->fd, "testing callbacks\n");
00835    ao2_t_callback(c1, 0, print_cb, a, "test callback");
00836 
00837    ast_cli(a->fd, "testing container cloning\n");
00838    c2 = ao2_container_clone(c1, 0);
00839    if (ao2_container_count(c1) != ao2_container_count(c2)) {
00840       ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
00841    }
00842    ao2_t_callback(c2, 0, print_cb, a, "test callback");
00843 
00844    ast_cli(a->fd, "testing iterators, remove every second object\n");
00845    {
00846       struct ao2_iterator ai;
00847       int x = 0;
00848 
00849       ai = ao2_iterator_init(c1, 0);
00850       while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
00851          ast_cli(a->fd, "iterator on <%s>\n", obj);
00852          if (x++ & 1)
00853             ao2_t_unlink(c1, obj,"test");
00854          ao2_t_ref(obj, -1,"test");
00855       }
00856       ao2_iterator_destroy(&ai);
00857       ast_cli(a->fd, "testing iterators again\n");
00858       ai = ao2_iterator_init(c1, 0);
00859       while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
00860          ast_cli(a->fd, "iterator on <%s>\n", obj);
00861          ao2_t_ref(obj, -1,"test");
00862       }
00863       ao2_iterator_destroy(&ai);
00864    }
00865 
00866    ast_cli(a->fd, "testing callbacks again\n");
00867    ao2_t_callback(c1, 0, print_cb, a, "test callback");
00868 
00869    ast_verbose("now you should see an error and possible assertion failure messages:\n");
00870    ao2_t_ref(&i, -1, "");  /* i is not a valid object so we print an error here */
00871 
00872    ast_cli(a->fd, "destroy container\n");
00873    ao2_t_ref(c1, -1, "");  /* destroy container */
00874    ao2_t_ref(c2, -1, "");  /* destroy container */
00875    handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
00876    return CLI_SUCCESS;
00877 }
00878 #endif /* AO2_DEBUG */
00879 
00880 #if defined(AO2_DEBUG)
00881 static struct ast_cli_entry cli_astobj2[] = {
00882    AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
00883    AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
00884 };
00885 #endif /* AO2_DEBUG */
00886 
00887 static void astobj2_cleanup(void)
00888 {
00889 #if defined(AO2_DEBUG)
00890    ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
00891 #endif
00892 #ifdef REF_DEBUG
00893    fclose(ref_log);
00894    ref_log = NULL;
00895 #endif
00896 }
00897 
00898 int astobj2_init(void)
00899 {
00900 #ifdef REF_DEBUG
00901    char ref_filename[1024];
00902 #endif
00903 
00904    if (container_init() != 0) {
00905       return -1;
00906    }
00907 
00908 #ifdef REF_DEBUG
00909    snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
00910    ref_log = fopen(ref_filename, "w");
00911    if (!ref_log) {
00912       ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
00913    }
00914 #endif
00915 
00916 #if defined(AO2_DEBUG)
00917    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
00918 #endif   /* defined(AO2_DEBUG) */
00919 
00920    ast_register_cleanup(astobj2_cleanup);
00921 
00922    return 0;
00923 }

Generated on Thu Apr 16 06:27:14 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6