astobj2.c 23 KB

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