/media/libnestegg/src/halloc.c

http://github.com/zpao/v8monkey · C · 254 lines · 149 code · 44 blank · 61 comment · 22 complexity · 666028427f11727fabbec80a0ef9bacf MD5 · raw file

  1. /*
  2. * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved.
  3. *
  4. * Hierarchical memory allocator, 1.2.1
  5. * http://swapped.cc/halloc
  6. */
  7. /*
  8. * The program is distributed under terms of BSD license.
  9. * You can obtain the copy of the license by visiting:
  10. *
  11. * http://www.opensource.org/licenses/bsd-license.php
  12. */
  13. #include <stdlib.h> /* realloc */
  14. #include <string.h> /* memset & co */
  15. #include "halloc.h"
  16. #include "align.h"
  17. #include "hlist.h"
  18. /*
  19. * block control header
  20. */
  21. typedef struct hblock
  22. {
  23. #ifndef NDEBUG
  24. #define HH_MAGIC 0x20040518L
  25. long magic;
  26. #endif
  27. hlist_item_t siblings; /* 2 pointers */
  28. hlist_head_t children; /* 1 pointer */
  29. max_align_t data[1]; /* not allocated, see below */
  30. } hblock_t;
  31. #define sizeof_hblock offsetof(hblock_t, data)
  32. /*
  33. *
  34. */
  35. realloc_t halloc_allocator = NULL;
  36. #define allocator halloc_allocator
  37. /*
  38. * static methods
  39. */
  40. static void _set_allocator(void);
  41. static void * _realloc(void * ptr, size_t n);
  42. static int _relate(hblock_t * b, hblock_t * p);
  43. static void _free_children(hblock_t * p);
  44. /*
  45. * Core API
  46. */
  47. void * halloc(void * ptr, size_t len)
  48. {
  49. hblock_t * p;
  50. /* set up default allocator */
  51. if (! allocator)
  52. {
  53. _set_allocator();
  54. assert(allocator);
  55. }
  56. /* calloc */
  57. if (! ptr)
  58. {
  59. if (! len)
  60. return NULL;
  61. p = allocator(0, len + sizeof_hblock);
  62. if (! p)
  63. return NULL;
  64. #ifndef NDEBUG
  65. p->magic = HH_MAGIC;
  66. #endif
  67. hlist_init(&p->children);
  68. hlist_init_item(&p->siblings);
  69. return p->data;
  70. }
  71. p = structof(ptr, hblock_t, data);
  72. assert(p->magic == HH_MAGIC);
  73. /* realloc */
  74. if (len)
  75. {
  76. p = allocator(p, len + sizeof_hblock);
  77. if (! p)
  78. return NULL;
  79. hlist_relink(&p->siblings);
  80. hlist_relink_head(&p->children);
  81. return p->data;
  82. }
  83. /* free */
  84. _free_children(p);
  85. hlist_del(&p->siblings);
  86. allocator(p, 0);
  87. return NULL;
  88. }
  89. void hattach(void * block, void * parent)
  90. {
  91. hblock_t * b, * p;
  92. if (! block)
  93. {
  94. assert(! parent);
  95. return;
  96. }
  97. /* detach */
  98. b = structof(block, hblock_t, data);
  99. assert(b->magic == HH_MAGIC);
  100. hlist_del(&b->siblings);
  101. if (! parent)
  102. return;
  103. /* attach */
  104. p = structof(parent, hblock_t, data);
  105. assert(p->magic == HH_MAGIC);
  106. /* sanity checks */
  107. assert(b != p); /* trivial */
  108. assert(! _relate(p, b)); /* heavy ! */
  109. hlist_add(&p->children, &b->siblings);
  110. }
  111. /*
  112. * malloc/free api
  113. */
  114. void * h_malloc(size_t len)
  115. {
  116. return halloc(0, len);
  117. }
  118. void * h_calloc(size_t n, size_t len)
  119. {
  120. void * ptr = halloc(0, len*=n);
  121. return ptr ? memset(ptr, 0, len) : NULL;
  122. }
  123. void * h_realloc(void * ptr, size_t len)
  124. {
  125. return halloc(ptr, len);
  126. }
  127. void h_free(void * ptr)
  128. {
  129. halloc(ptr, 0);
  130. }
  131. char * h_strdup(const char * str)
  132. {
  133. size_t len = strlen(str);
  134. char * ptr = halloc(0, len + 1);
  135. return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL;
  136. }
  137. /*
  138. * static stuff
  139. */
  140. static void _set_allocator(void)
  141. {
  142. void * p;
  143. assert(! allocator);
  144. /*
  145. * the purpose of the test below is to check the behaviour
  146. * of realloc(ptr, 0), which is defined in the standard
  147. * as an implementation-specific. if it returns zero,
  148. * then it's equivalent to free(). it can however return
  149. * non-zero, in which case it cannot be used for freeing
  150. * memory blocks and we'll need to supply our own version
  151. *
  152. * Thanks to Stan Tobias for pointing this tricky part out.
  153. */
  154. allocator = realloc;
  155. if (! (p = malloc(1)))
  156. /* hmm */
  157. return;
  158. if ((p = realloc(p, 0)))
  159. {
  160. /* realloc cannot be used as free() */
  161. allocator = _realloc;
  162. free(p);
  163. }
  164. }
  165. static void * _realloc(void * ptr, size_t n)
  166. {
  167. /*
  168. * free'ing realloc()
  169. */
  170. if (n)
  171. return realloc(ptr, n);
  172. free(ptr);
  173. return NULL;
  174. }
  175. static int _relate(hblock_t * b, hblock_t * p)
  176. {
  177. hlist_item_t * i;
  178. if (!b || !p)
  179. return 0;
  180. /*
  181. * since there is no 'parent' pointer, which would've allowed
  182. * O(log(n)) upward traversal, the check must use O(n) downward
  183. * iteration of the entire hierarchy; and this can be VERY SLOW
  184. */
  185. hlist_for_each(i, &p->children)
  186. {
  187. hblock_t * q = structof(i, hblock_t, siblings);
  188. if (q == b || _relate(b, q))
  189. return 1;
  190. }
  191. return 0;
  192. }
  193. static void _free_children(hblock_t * p)
  194. {
  195. hlist_item_t * i, * tmp;
  196. #ifndef NDEBUG
  197. /*
  198. * this catches loops in hierarchy with almost zero
  199. * overhead (compared to _relate() running time)
  200. */
  201. assert(p && p->magic == HH_MAGIC);
  202. p->magic = 0;
  203. #endif
  204. hlist_for_each_safe(i, tmp, &p->children)
  205. {
  206. hblock_t * q = structof(i, hblock_t, siblings);
  207. _free_children(q);
  208. allocator(q, 0);
  209. }
  210. }