hashtab.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2007, Digium, Inc.
  5. *
  6. * Steve Murphy <murf@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief code to implement generic hash tables
  21. *
  22. * \author Steve Murphy <murf@digium.com>
  23. */
  24. /*** MODULEINFO
  25. <support_level>core</support_level>
  26. ***/
  27. #include "asterisk.h"
  28. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  29. #include <ctype.h>
  30. #include "asterisk/lock.h"
  31. #include "asterisk/frame.h"
  32. #include "asterisk/channel.h"
  33. #include "asterisk/cli.h"
  34. #include "asterisk/term.h"
  35. #include "asterisk/utils.h"
  36. #include "asterisk/threadstorage.h"
  37. #include "asterisk/linkedlists.h"
  38. #include "asterisk/hashtab.h"
  39. #ifdef __AST_DEBUG_MALLOC
  40. static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func);
  41. #define ast_hashtab_resize(a) _ast_hashtab_resize(a,__FILE__, __LINE__, __PRETTY_FUNCTION__)
  42. #else
  43. static void ast_hashtab_resize(struct ast_hashtab *tab);
  44. #endif
  45. static void *ast_hashtab_lookup_internal(struct ast_hashtab *tab, const void *obj, unsigned int h);
  46. /* some standard, default routines for general use */
  47. int ast_hashtab_compare_strings(const void *a, const void *b)
  48. {
  49. return strcmp(a, b);
  50. }
  51. int ast_hashtab_compare_strings_nocase(const void *a, const void *b)
  52. {
  53. return strcasecmp(a, b);
  54. }
  55. int ast_hashtab_compare_ints(const void *a, const void *b)
  56. {
  57. int ai = *((int *) a);
  58. int bi = *((int *) b);
  59. if (ai < bi)
  60. return -1;
  61. return !(ai == bi);
  62. }
  63. int ast_hashtab_compare_shorts(const void *a, const void *b)
  64. {
  65. short as = *((short *) a);
  66. short bs = *((short *) b);
  67. if (as < bs)
  68. return -1;
  69. return !(as == bs);
  70. }
  71. int ast_hashtab_resize_java(struct ast_hashtab *tab)
  72. {
  73. double loadfactor = (double) tab->hash_tab_elements / (double) tab->hash_tab_size;
  74. return (loadfactor > 0.75);
  75. }
  76. int ast_hashtab_resize_tight(struct ast_hashtab *tab)
  77. {
  78. return (tab->hash_tab_elements > tab->hash_tab_size); /* this is quicker than division */
  79. }
  80. int ast_hashtab_resize_none(struct ast_hashtab *tab) /* always return 0 -- no resizing */
  81. {
  82. return 0;
  83. }
  84. int ast_is_prime(int num)
  85. {
  86. int tnum, limit;
  87. if (!(num & 0x1)) /* even number -- not prime */
  88. return 0;
  89. /* Loop through ODD numbers starting with 3 */
  90. tnum = 3;
  91. limit = num;
  92. while (tnum < limit) {
  93. if (!(num % tnum))
  94. return 0;
  95. /* really, we only need to check sqrt(num) numbers */
  96. limit = num / tnum;
  97. /* we only check odd numbers */
  98. tnum = tnum + 2;
  99. }
  100. /* if we made it through the loop, the number is a prime */
  101. return 1;
  102. }
  103. int ast_hashtab_newsize_java(struct ast_hashtab *tab)
  104. {
  105. int i = (tab->hash_tab_size << 1); /* multiply by two */
  106. while (!ast_is_prime(i))
  107. i++;
  108. return i;
  109. }
  110. int ast_hashtab_newsize_tight(struct ast_hashtab *tab)
  111. {
  112. int x = (tab->hash_tab_size << 1);
  113. int i = (tab->hash_tab_size + x);
  114. while (!ast_is_prime(i))
  115. i++;
  116. return i;
  117. }
  118. int ast_hashtab_newsize_none(struct ast_hashtab *tab) /* always return current size -- no resizing */
  119. {
  120. return tab->hash_tab_size;
  121. }
  122. unsigned int ast_hashtab_hash_string(const void *obj)
  123. {
  124. unsigned char *str = (unsigned char *) obj;
  125. unsigned int total;
  126. for (total = 0; *str; str++) {
  127. unsigned int tmp = total;
  128. total <<= 1; /* multiply by 2 */
  129. total += tmp; /* multiply by 3 */
  130. total <<= 2; /* multiply by 12 */
  131. total += tmp; /* multiply by 13 */
  132. total += ((unsigned int)(*str));
  133. }
  134. return total;
  135. }
  136. unsigned int ast_hashtab_hash_string_sax(const void *obj) /* from Josh */
  137. {
  138. const unsigned char *str = obj;
  139. unsigned int total = 0, c = 0;
  140. while ((c = *str++))
  141. total ^= (total << 5) + (total >> 2) + (total << 10) + c;
  142. return total;
  143. }
  144. unsigned int ast_hashtab_hash_string_nocase(const void *obj)
  145. {
  146. const unsigned char *str = obj;
  147. unsigned int total;
  148. for (total = 0; *str; str++) {
  149. unsigned int tmp = total;
  150. unsigned int charval = toupper(*str);
  151. /* hopefully, the following is faster than multiplication by 7 */
  152. /* why do I go to this bother? A good compiler will do this
  153. anyway, if I say total *= 13 */
  154. /* BTW, tried *= 7, and it doesn't do as well in spreading things around! */
  155. total <<= 1; /* multiply by 2 */
  156. total += tmp; /* multiply by 3 */
  157. total <<= 2; /* multiply by 12 */
  158. total += tmp; /* multiply by 13 */
  159. total += (charval);
  160. }
  161. return total;
  162. }
  163. unsigned int ast_hashtab_hash_int(const int x)
  164. {
  165. return x;
  166. }
  167. unsigned int ast_hashtab_hash_short(const short x)
  168. {
  169. /* hmmmm.... modulus is best < 65535 !! */
  170. return x;
  171. }
  172. struct ast_hashtab *
  173. #ifdef __AST_DEBUG_MALLOC
  174. _ast_hashtab_create
  175. #else
  176. ast_hashtab_create
  177. #endif
  178. (int initial_buckets,
  179. int (*compare)(const void *a, const void *b),
  180. int (*resize)(struct ast_hashtab *),
  181. int (*newsize)(struct ast_hashtab *tab),
  182. unsigned int (*hash)(const void *obj),
  183. int do_locking
  184. #ifdef __AST_DEBUG_MALLOC
  185. , const char *file, int lineno, const char *function
  186. #endif
  187. )
  188. {
  189. struct ast_hashtab *ht;
  190. #ifdef __AST_DEBUG_MALLOC
  191. if (!(ht = __ast_calloc(1, sizeof(*ht), file, lineno, function)))
  192. #else
  193. if (!(ht = ast_calloc(1, sizeof(*ht))))
  194. #endif
  195. return NULL;
  196. while (!ast_is_prime(initial_buckets)) /* make sure this is prime */
  197. initial_buckets++;
  198. #ifdef __AST_DEBUG_MALLOC
  199. if (!(ht->array = __ast_calloc(initial_buckets, sizeof(*(ht->array)), file, lineno, function))) {
  200. #else
  201. if (!(ht->array = ast_calloc(initial_buckets, sizeof(*(ht->array))))) {
  202. #endif
  203. ast_free(ht);
  204. return NULL;
  205. }
  206. ht->hash_tab_size = initial_buckets;
  207. ht->compare = compare;
  208. ht->resize = resize;
  209. ht->newsize = newsize;
  210. ht->hash = hash;
  211. ht->do_locking = do_locking;
  212. if (do_locking)
  213. ast_rwlock_init(&ht->lock);
  214. if (!ht->resize)
  215. ht->resize = ast_hashtab_resize_java;
  216. if (!ht->newsize)
  217. ht->newsize = ast_hashtab_newsize_java;
  218. return ht;
  219. }
  220. #ifdef __AST_DEBUG_MALLOC
  221. struct ast_hashtab *_ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj), const char *file, int lineno, const char *func)
  222. #else
  223. struct ast_hashtab *ast_hashtab_dup(struct ast_hashtab *tab, void *(*obj_dup_func)(const void *obj))
  224. #endif
  225. {
  226. struct ast_hashtab *ht;
  227. unsigned int i;
  228. if (!(ht = ast_calloc(1, sizeof(*ht))))
  229. return NULL;
  230. if (!(ht->array =
  231. #ifdef __AST_DEBUG_MALLOC
  232. __ast_calloc(tab->hash_tab_size, sizeof(*(ht->array)), file, lineno, func)
  233. #else
  234. ast_calloc(tab->hash_tab_size, sizeof(*(ht->array)))
  235. #endif
  236. )) {
  237. ast_free(ht);
  238. return NULL;
  239. }
  240. ht->hash_tab_size = tab->hash_tab_size;
  241. ht->compare = tab->compare;
  242. ht->resize = tab->resize;
  243. ht->newsize = tab->newsize;
  244. ht->hash = tab->hash;
  245. ht->do_locking = tab->do_locking;
  246. if (ht->do_locking)
  247. ast_rwlock_init(&ht->lock);
  248. /* now, dup the objects in the buckets and get them into the table */
  249. /* the fast way is to use the existing array index, and not have to hash
  250. the objects again */
  251. for (i = 0; i < ht->hash_tab_size; i++) {
  252. struct ast_hashtab_bucket *b = tab->array[i];
  253. while (b) {
  254. void *newobj = (*obj_dup_func)(b->object);
  255. if (newobj)
  256. #ifdef __AST_DEBUG_MALLOC
  257. _ast_hashtab_insert_immediate_bucket(ht, newobj, i, file, lineno, func);
  258. #else
  259. ast_hashtab_insert_immediate_bucket(ht, newobj, i);
  260. #endif
  261. b = b->next;
  262. }
  263. }
  264. return ht;
  265. }
  266. static void tlist_del_item(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
  267. {
  268. /* item had better be in the list! or suffer the weirdness that occurs, later! */
  269. if (*head == item) { /* first item in the list */
  270. *head = item->tnext;
  271. if (item->tnext)
  272. item->tnext->tprev = NULL;
  273. } else {
  274. /* short circuit stuff */
  275. item->tprev->tnext = item->tnext;
  276. if (item->tnext)
  277. item->tnext->tprev = item->tprev;
  278. }
  279. }
  280. static void tlist_add_head(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
  281. {
  282. if (*head) {
  283. item->tnext = *head;
  284. item->tprev = NULL;
  285. (*head)->tprev = item;
  286. *head = item;
  287. } else {
  288. /* the list is empty */
  289. *head = item;
  290. item->tprev = NULL;
  291. item->tnext = NULL;
  292. }
  293. }
  294. /* user-controlled hashtab locking. Create a hashtab without locking, then call the
  295. following locking routines yourself to lock the table between threads. */
  296. void ast_hashtab_wrlock(struct ast_hashtab *tab)
  297. {
  298. ast_rwlock_wrlock(&tab->lock);
  299. }
  300. void ast_hashtab_rdlock(struct ast_hashtab *tab)
  301. {
  302. ast_rwlock_rdlock(&tab->lock);
  303. }
  304. void ast_hashtab_initlock(struct ast_hashtab *tab)
  305. {
  306. ast_rwlock_init(&tab->lock);
  307. }
  308. void ast_hashtab_destroylock(struct ast_hashtab *tab)
  309. {
  310. ast_rwlock_destroy(&tab->lock);
  311. }
  312. void ast_hashtab_unlock(struct ast_hashtab *tab)
  313. {
  314. ast_rwlock_unlock(&tab->lock);
  315. }
  316. void ast_hashtab_destroy(struct ast_hashtab *tab, void (*objdestroyfunc)(void *obj))
  317. {
  318. /* this func will free the hash table and all its memory. It
  319. doesn't touch the objects stored in it */
  320. if (tab) {
  321. if (tab->do_locking)
  322. ast_rwlock_wrlock(&tab->lock);
  323. if (tab->array) {
  324. /* go thru and destroy the buckets */
  325. struct ast_hashtab_bucket *t;
  326. int i;
  327. while (tab->tlist) {
  328. t = tab->tlist;
  329. if (t->object && objdestroyfunc) {
  330. /* I cast this because I'm not going to MOD it, I'm going to DESTROY
  331. * it.
  332. */
  333. (*objdestroyfunc)((void *) t->object);
  334. }
  335. tlist_del_item(&(tab->tlist), tab->tlist);
  336. ast_free(t);
  337. }
  338. for (i = 0; i < tab->hash_tab_size; i++) {
  339. /* Not totally necessary, but best to destroy old pointers */
  340. tab->array[i] = NULL;
  341. }
  342. ast_free(tab->array);
  343. }
  344. if (tab->do_locking) {
  345. ast_rwlock_unlock(&tab->lock);
  346. ast_rwlock_destroy(&tab->lock);
  347. }
  348. ast_free(tab);
  349. }
  350. }
  351. #ifdef __AST_DEBUG_MALLOC
  352. int _ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func)
  353. #else
  354. int ast_hashtab_insert_immediate(struct ast_hashtab *tab, const void *obj)
  355. #endif
  356. {
  357. unsigned int h;
  358. int res=0;
  359. if (!tab || !obj)
  360. return res;
  361. if (tab->do_locking)
  362. ast_rwlock_wrlock(&tab->lock);
  363. h = (*tab->hash)(obj) % tab->hash_tab_size;
  364. #ifdef __AST_DEBUG_MALLOC
  365. res = _ast_hashtab_insert_immediate_bucket(tab, obj, h, file, lineno, func);
  366. #else
  367. res = ast_hashtab_insert_immediate_bucket(tab, obj, h);
  368. #endif
  369. if (tab->do_locking)
  370. ast_rwlock_unlock(&tab->lock);
  371. return res;
  372. }
  373. #ifdef __AST_DEBUG_MALLOC
  374. int _ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h, const char *file, int lineno, const char *func)
  375. #else
  376. int ast_hashtab_insert_immediate_bucket(struct ast_hashtab *tab, const void *obj, unsigned int h)
  377. #endif
  378. {
  379. int c;
  380. struct ast_hashtab_bucket *b;
  381. if (!tab || !obj)
  382. return 0;
  383. for (c = 0, b = tab->array[h]; b; b= b->next)
  384. c++;
  385. if (c + 1 > tab->largest_bucket_size)
  386. tab->largest_bucket_size = c + 1;
  387. if (!(b =
  388. #ifdef __AST_DEBUG_MALLOC
  389. __ast_calloc(1, sizeof(*b), file, lineno, func)
  390. #else
  391. ast_calloc(1, sizeof(*b))
  392. #endif
  393. )) return 0;
  394. b->object = obj;
  395. b->next = tab->array[h];
  396. tab->array[h] = b;
  397. if (b->next)
  398. b->next->prev = b;
  399. tlist_add_head(&(tab->tlist), b);
  400. tab->hash_tab_elements++;
  401. if ((*tab->resize)(tab))
  402. ast_hashtab_resize(tab);
  403. return 1;
  404. }
  405. #ifdef __AST_DEBUG_MALLOC
  406. int _ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj, const char *file, int lineno, const char *func)
  407. #else
  408. int ast_hashtab_insert_safe(struct ast_hashtab *tab, const void *obj)
  409. #endif
  410. {
  411. /* check to see if the element is already there; insert only if
  412. it is not there. */
  413. /* will force a resize if the resize func returns 1 */
  414. /* returns 1 on success, 0 if there's a problem, or it's already there. */
  415. unsigned int bucket = 0;
  416. if (tab->do_locking)
  417. ast_rwlock_wrlock(&tab->lock);
  418. if (!ast_hashtab_lookup_bucket(tab, obj, &bucket)) {
  419. #ifdef __AST_DEBUG_MALLOC
  420. int ret2 = _ast_hashtab_insert_immediate_bucket(tab, obj, bucket, file, lineno, func);
  421. #else
  422. int ret2 = ast_hashtab_insert_immediate_bucket(tab, obj, bucket);
  423. #endif
  424. if (tab->do_locking)
  425. ast_rwlock_unlock(&tab->lock);
  426. return ret2;
  427. }
  428. if (tab->do_locking)
  429. ast_rwlock_unlock(&tab->lock);
  430. return 0;
  431. }
  432. void *ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
  433. {
  434. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  435. unsigned int h;
  436. void *ret;
  437. if (!tab || !obj)
  438. return 0;
  439. if (tab->do_locking)
  440. ast_rwlock_rdlock(&tab->lock);
  441. h = (*tab->hash)(obj) % tab->hash_tab_size;
  442. ret = ast_hashtab_lookup_internal(tab,obj,h);
  443. if (tab->do_locking)
  444. ast_rwlock_unlock(&tab->lock);
  445. return ret;
  446. }
  447. void *ast_hashtab_lookup_with_hash(struct ast_hashtab *tab, const void *obj, unsigned int hashval)
  448. {
  449. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  450. unsigned int h;
  451. void *ret;
  452. if (!tab || !obj)
  453. return 0;
  454. if (tab->do_locking)
  455. ast_rwlock_rdlock(&tab->lock);
  456. h = hashval % tab->hash_tab_size;
  457. ret = ast_hashtab_lookup_internal(tab,obj,h);
  458. if (tab->do_locking)
  459. ast_rwlock_unlock(&tab->lock);
  460. return ret;
  461. }
  462. void *ast_hashtab_lookup_bucket(struct ast_hashtab *tab, const void *obj, unsigned int *bucket)
  463. {
  464. /* lookup this object in the hash table. return a ptr if found, or NULL if not */
  465. unsigned int h;
  466. void *ret;
  467. if (!tab || !obj)
  468. return 0;
  469. h = (*tab->hash)(obj) % tab->hash_tab_size;
  470. ret = ast_hashtab_lookup_internal(tab,obj,h);
  471. *bucket = h;
  472. return ret;
  473. }
  474. static void *ast_hashtab_lookup_internal(struct ast_hashtab *tab, const void *obj, unsigned int h)
  475. {
  476. struct ast_hashtab_bucket *b;
  477. for (b = tab->array[h]; b; b = b->next) {
  478. if (!(*tab->compare)(obj,b->object)) {
  479. /* I can't touch obj in this func, but the outside world is welcome to */
  480. return (void*) b->object;
  481. }
  482. }
  483. return NULL;
  484. }
  485. void ast_hashtab_get_stats(struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets)
  486. {
  487. /* returns key stats for the table */
  488. if (tab->do_locking)
  489. ast_rwlock_rdlock(&tab->lock);
  490. *biggest_bucket_size = tab->largest_bucket_size;
  491. *resize_count = tab->resize_count;
  492. *num_objects = tab->hash_tab_elements;
  493. *num_buckets = tab->hash_tab_size;
  494. if (tab->do_locking)
  495. ast_rwlock_unlock(&tab->lock);
  496. }
  497. /* this function returns the number of elements stored in the hashtab */
  498. int ast_hashtab_size(struct ast_hashtab *tab)
  499. {
  500. return tab->hash_tab_elements;
  501. }
  502. /* this function returns the size of the bucket array in the hashtab */
  503. int ast_hashtab_capacity( struct ast_hashtab *tab)
  504. {
  505. return tab->hash_tab_size;
  506. }
  507. /* the insert operation calls this, and is wrlock'd when it does. */
  508. /* if you want to call it, you should set the wrlock yourself */
  509. #ifdef __AST_DEBUG_MALLOC
  510. static void _ast_hashtab_resize(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  511. #else
  512. static void ast_hashtab_resize(struct ast_hashtab *tab)
  513. #endif
  514. {
  515. /* this function is called either internally, when the resize func returns 1, or
  516. externally by the user to force a resize of the hash table */
  517. int newsize = (*tab->newsize)(tab), i, c;
  518. unsigned int h;
  519. struct ast_hashtab_bucket *b,*bn;
  520. /* Since we keep a DLL of all the buckets in tlist,
  521. all we have to do is free the array, malloc a new one,
  522. and then go thru the tlist array and reassign them into
  523. the bucket arrayj.
  524. */
  525. for (i = 0; i < tab->hash_tab_size; i++) { /* don't absolutely have to do this, but
  526. why leave ptrs laying around */
  527. tab->array[i] = 0; /* erase old ptrs */
  528. }
  529. ast_free(tab->array);
  530. if (!(tab->array =
  531. #ifdef __AST_DEBUG_MALLOC
  532. __ast_calloc(newsize, sizeof(*(tab->array)), file, lineno, func)
  533. #else
  534. ast_calloc(newsize, sizeof(*(tab->array)))
  535. #endif
  536. ))
  537. return;
  538. /* now sort the buckets into their rightful new slots */
  539. tab->resize_count++;
  540. tab->hash_tab_size = newsize;
  541. tab->largest_bucket_size = 0;
  542. for (b = tab->tlist; b; b = bn) {
  543. b->prev = 0;
  544. bn = b->tnext;
  545. h = (*tab->hash)(b->object) % tab->hash_tab_size;
  546. b->next = tab->array[h];
  547. if (b->next)
  548. b->next->prev = b;
  549. tab->array[h] = b;
  550. }
  551. /* recalc the largest bucket size */
  552. for (i = 0; i < tab->hash_tab_size; i++) {
  553. for (c = 0, b = tab->array[i]; b; b = b->next)
  554. c++;
  555. if (c > tab->largest_bucket_size)
  556. tab->largest_bucket_size = c;
  557. }
  558. }
  559. #ifdef __AST_DEBUG_MALLOC
  560. struct ast_hashtab_iter *_ast_hashtab_start_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  561. #else
  562. struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab)
  563. #endif
  564. {
  565. /* returns an iterator */
  566. struct ast_hashtab_iter *it;
  567. if (!(it =
  568. #ifdef __AST_DEBUG_MALLOC
  569. __ast_calloc(1, sizeof(*it), file, lineno, func)
  570. #else
  571. ast_calloc(1, sizeof(*it))
  572. #endif
  573. ))
  574. return NULL;
  575. it->next = tab->tlist;
  576. it->tab = tab;
  577. if (tab->do_locking)
  578. ast_rwlock_rdlock(&tab->lock);
  579. return it;
  580. }
  581. /* use this function to get a write lock */
  582. #ifdef __AST_DEBUG_MALLOC
  583. struct ast_hashtab_iter *_ast_hashtab_start_write_traversal(struct ast_hashtab *tab, const char *file, int lineno, const char *func)
  584. #else
  585. struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *tab)
  586. #endif
  587. {
  588. /* returns an iterator */
  589. struct ast_hashtab_iter *it;
  590. if (!(it =
  591. #ifdef __AST_DEBUG_MALLOC
  592. __ast_calloc(1, sizeof(*it), file, lineno, func)
  593. #else
  594. ast_calloc(1, sizeof(*it))
  595. #endif
  596. ))
  597. return NULL;
  598. it->next = tab->tlist;
  599. it->tab = tab;
  600. if (tab->do_locking)
  601. ast_rwlock_wrlock(&tab->lock);
  602. return it;
  603. }
  604. void ast_hashtab_end_traversal(struct ast_hashtab_iter *it)
  605. {
  606. if (!it)
  607. return;
  608. if (it->tab->do_locking)
  609. ast_rwlock_unlock(&it->tab->lock);
  610. ast_free(it);
  611. }
  612. void *ast_hashtab_next(struct ast_hashtab_iter *it)
  613. {
  614. /* returns the next object in the list, advances iter one step */
  615. struct ast_hashtab_bucket *retval;
  616. if (it && it->next) { /* there's a next in the bucket list */
  617. retval = it->next;
  618. it->next = retval->tnext;
  619. return (void *) retval->object;
  620. }
  621. return NULL;
  622. }
  623. static void *ast_hashtab_remove_object_internal(struct ast_hashtab *tab, struct ast_hashtab_bucket *b, int h)
  624. {
  625. const void *obj2;
  626. if (b->prev)
  627. b->prev->next = b->next;
  628. else
  629. tab->array[h] = b->next;
  630. if (b->next)
  631. b->next->prev = b->prev;
  632. tlist_del_item(&(tab->tlist), b);
  633. obj2 = b->object;
  634. b->object = b->next = (void*)2;
  635. ast_free(b); /* free up the hashbucket */
  636. tab->hash_tab_elements--;
  637. #ifdef DEBUG
  638. {
  639. int c2;
  640. struct ast_hashtab_bucket *b2;
  641. /* do a little checking */
  642. for (c2 = 0, b2 = tab->tlist; b2; b2 = b2->tnext) {
  643. c2++;
  644. }
  645. if (c2 != tab->hash_tab_elements) {
  646. printf("Hey! we didn't delete right! there are %d elements in the list, and we expected %d\n",
  647. c2, tab->hash_tab_elements);
  648. }
  649. for (c2 = 0, b2 = tab->tlist; b2; b2 = b2->tnext) {
  650. unsigned int obj3 = (unsigned long) obj2;
  651. unsigned int b3 = (unsigned long) b;
  652. if (b2->object == obj2)
  653. printf("Hey-- you've still got a bucket pointing at ht_element %x\n", obj3);
  654. if (b2->next == b)
  655. printf("Hey-- you've still got a bucket with next ptr pointing to deleted bucket %x\n", b3);
  656. if (b2->prev == b)
  657. printf("Hey-- you've still got a bucket with prev ptr pointing to deleted bucket %x\n", b3);
  658. if (b2->tprev == b)
  659. printf("Hey-- you've still got a bucket with tprev ptr pointing to deleted bucket %x\n", b3);
  660. if (b2->tnext == b)
  661. printf("Hey-- you've still got a bucket with tnext ptr pointing to deleted bucket %x\n", b3);
  662. }
  663. }
  664. #endif
  665. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  666. }
  667. void *ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
  668. {
  669. /* looks up the object; removes the corresponding bucket */
  670. const void *obj2;
  671. if (!tab || !obj)
  672. return 0;
  673. if (tab->do_locking)
  674. ast_rwlock_wrlock(&tab->lock);
  675. obj2 = ast_hashtab_remove_object_via_lookup_nolock(tab,obj);
  676. if (tab->do_locking)
  677. ast_rwlock_unlock(&tab->lock);
  678. return (void *)obj2;
  679. }
  680. void *ast_hashtab_remove_object_via_lookup_nolock(struct ast_hashtab *tab, void *obj)
  681. {
  682. /* looks up the object; removes the corresponding bucket */
  683. unsigned int h;
  684. struct ast_hashtab_bucket *b;
  685. if (!tab || !obj)
  686. return 0;
  687. h = (*tab->hash)(obj) % tab->hash_tab_size;
  688. for (b = tab->array[h]; b; b = b->next) {
  689. if (!(*tab->compare)(obj, b->object)) {
  690. const void *obj2;
  691. obj2 = ast_hashtab_remove_object_internal(tab, b, h);
  692. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  693. }
  694. }
  695. return 0;
  696. }
  697. void *ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj)
  698. {
  699. /* looks up the object by hash and then comparing pts in bucket list instead of
  700. calling the compare routine; removes the bucket -- a slightly cheaper operation */
  701. /* looks up the object; removes the corresponding bucket */
  702. const void *obj2;
  703. if (!tab || !obj)
  704. return 0;
  705. if (tab->do_locking)
  706. ast_rwlock_wrlock(&tab->lock);
  707. obj2 = ast_hashtab_remove_this_object_nolock(tab,obj);
  708. if (tab->do_locking)
  709. ast_rwlock_unlock(&tab->lock);
  710. return (void *)obj2;
  711. }
  712. void *ast_hashtab_remove_this_object_nolock(struct ast_hashtab *tab, void *obj)
  713. {
  714. /* looks up the object by hash and then comparing pts in bucket list instead of
  715. calling the compare routine; removes the bucket -- a slightly cheaper operation */
  716. /* looks up the object; removes the corresponding bucket */
  717. unsigned int h;
  718. struct ast_hashtab_bucket *b;
  719. if (!tab || !obj)
  720. return 0;
  721. h = (*tab->hash)(obj) % tab->hash_tab_size;
  722. for (b = tab->array[h]; b; b = b->next) {
  723. if (obj == b->object) {
  724. const void *obj2;
  725. obj2 = ast_hashtab_remove_object_internal(tab, b, h);
  726. return (void *) obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
  727. }
  728. }
  729. return 0;
  730. }