db_salloc.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_salloc.c,v 11.10 2000/12/06 19:55:44 ubell Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. /*
  18.  * Implement shared memory region allocation, using simple first-fit algorithm.
  19.  * The model is that we take a "chunk" of shared memory store and begin carving
  20.  * it up into areas, similarly to how malloc works.  We do coalescing on free.
  21.  *
  22.  * The "len" field in the __data struct contains the length of the free region
  23.  * (less the size_t bytes that holds the length).  We use the address provided
  24.  * by the caller to find this length, which allows us to free a chunk without
  25.  * requiring that the caller pass in the length of the chunk they're freeing.
  26.  */
  27. SH_LIST_HEAD(__head);
  28. struct __data {
  29. size_t len;
  30. SH_LIST_ENTRY links;
  31. };
  32. /*
  33.  * __db_shalloc_init --
  34.  * Initialize the area as one large chunk.
  35.  *
  36.  * PUBLIC: void __db_shalloc_init __P((void *, size_t));
  37.  */
  38. void
  39. __db_shalloc_init(area, size)
  40. void *area;
  41. size_t size;
  42. {
  43. struct __data *elp;
  44. struct __head *hp;
  45. hp = area;
  46. SH_LIST_INIT(hp);
  47. elp = (struct __data *)(hp + 1);
  48. elp->len = size - sizeof(struct __head) - sizeof(elp->len);
  49. SH_LIST_INSERT_HEAD(hp, elp, links, __data);
  50. }
  51. /*
  52.  * __db_shalloc --
  53.  * Allocate some space from the shared region.
  54.  *
  55.  * PUBLIC: int __db_shalloc_size __P((size_t, size_t));
  56.  */
  57. int
  58. __db_shalloc_size(len, align)
  59. size_t len, align;
  60. {
  61. /* Never allocate less than the size of a struct __data. */
  62. if (len < sizeof(struct __data))
  63. len = sizeof(struct __data);
  64. #ifdef DIAGNOSTIC
  65. /* Add room for a guard byte. */
  66. ++len;
  67. #endif
  68. /* Never align to less than a db_align_t boundary. */
  69. if (align <= sizeof(db_align_t))
  70. align = sizeof(db_align_t);
  71. return (ALIGN(len, align) + sizeof (struct __data));
  72. }
  73. /*
  74.  * __db_shalloc --
  75.  * Allocate some space from the shared region.
  76.  *
  77.  * PUBLIC: int __db_shalloc __P((void *, size_t, size_t, void *));
  78.  */
  79. int
  80. __db_shalloc(p, len, align, retp)
  81. void *p, *retp;
  82. size_t len, align;
  83. {
  84. struct __data *elp;
  85. size_t *sp;
  86. void *rp;
  87. /* Never allocate less than the size of a struct __data. */
  88. if (len < sizeof(struct __data))
  89. len = sizeof(struct __data);
  90. #ifdef DIAGNOSTIC
  91. /* Add room for a guard byte. */
  92. ++len;
  93. #endif
  94. /* Never align to less than a db_align_t boundary. */
  95. if (align <= sizeof(db_align_t))
  96. align = sizeof(db_align_t);
  97. /* Walk the list, looking for a slot. */
  98. for (elp = SH_LIST_FIRST((struct __head *)p, __data);
  99.     elp != NULL;
  100.     elp = SH_LIST_NEXT(elp, links, __data)) {
  101. /*
  102.  * Calculate the value of the returned pointer if we were to
  103.  * use this chunk.
  104.  * + Find the end of the chunk.
  105.  * + Subtract the memory the user wants.
  106.  * + Find the closest previous correctly-aligned address.
  107.  */
  108. rp = (u_int8_t *)elp + sizeof(size_t) + elp->len;
  109. rp = (u_int8_t *)rp - len;
  110. rp = (u_int8_t *)((db_alignp_t)rp & ~(align - 1));
  111. /*
  112.  * Rp may now point before elp->links, in which case the chunk
  113.  * was too small, and we have to try again.
  114.  */
  115. if ((u_int8_t *)rp < (u_int8_t *)&elp->links)
  116. continue;
  117. *(void **)retp = rp;
  118. #ifdef DIAGNOSTIC
  119. /*
  120.  * At this point, whether or not we still need to split up a
  121.  * chunk, retp is the address of the region we are returning,
  122.  * and (u_int8_t *)elp + sizeof(size_t) + elp->len gives us
  123.  * the address of the first byte after the end of the chunk.
  124.  * Make the byte immediately before that the guard byte.
  125.  */
  126. *((u_int8_t *)elp + sizeof(size_t) + elp->len - 1) = GUARD_BYTE;
  127. #endif
  128. #define SHALLOC_FRAGMENT 32
  129. /*
  130.  * If there are at least SHALLOC_FRAGMENT additional bytes of
  131.  * memory, divide the chunk into two chunks.
  132.  */
  133. if ((u_int8_t *)rp >=
  134.     (u_int8_t *)&elp->links + SHALLOC_FRAGMENT) {
  135. sp = rp;
  136. *--sp = elp->len -
  137.     ((u_int8_t *)rp - (u_int8_t *)&elp->links);
  138. elp->len -= *sp + sizeof(size_t);
  139. return (0);
  140. }
  141. /*
  142.  * Otherwise, we return the entire chunk, wasting some amount
  143.  * of space to keep the list compact.  However, because the
  144.  * address we're returning to the user may not be the address
  145.  * of the start of the region for alignment reasons, set the
  146.  * size_t length fields back to the "real" length field to a
  147.  * flag value, so that we can find the real length during free.
  148.  */
  149. #define ILLEGAL_SIZE 1
  150. SH_LIST_REMOVE(elp, links, __data);
  151. for (sp = rp; (u_int8_t *)--sp >= (u_int8_t *)&elp->links;)
  152. *sp = ILLEGAL_SIZE;
  153. return (0);
  154. }
  155. return (ENOMEM);
  156. }
  157. /*
  158.  * __db_shalloc_free --
  159.  * Free a shared memory allocation.
  160.  *
  161.  * PUBLIC: void __db_shalloc_free __P((void *, void *));
  162.  */
  163. void
  164. __db_shalloc_free(regionp, ptr)
  165. void *regionp, *ptr;
  166. {
  167. struct __data *elp, *lastp, *newp;
  168. struct __head *hp;
  169. size_t free_size, *sp;
  170. int merged;
  171. /*
  172.  * Step back over flagged length fields to find the beginning of
  173.  * the object and its real size.
  174.  */
  175. for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp)
  176. ;
  177. ptr = sp;
  178. newp = (struct __data *)((u_int8_t *)ptr - sizeof(size_t));
  179. free_size = newp->len;
  180. #ifdef DIAGNOSTIC
  181. /*
  182.  * The "real size" includes the guard byte;  it's just the last
  183.  * byte in the chunk, and the caller never knew it existed.
  184.  *
  185.  * Check it to make sure it hasn't been stomped.
  186.  */
  187. if (*((u_int8_t *)ptr + free_size - 1) != GUARD_BYTE) {
  188. /*
  189.  * Eventually, once we push a DB_ENV handle down to these
  190.  * routines, we should use the standard output channels.
  191.  */
  192. fprintf(stderr,
  193.     "Guard byte incorrect during shared memory free.n");
  194. abort();
  195. /* NOTREACHED */
  196. }
  197. /* Trash the returned memory (including guard byte). */
  198. memset(ptr, CLEAR_BYTE, free_size);
  199. #endif
  200. /*
  201.  * Walk the list, looking for where this entry goes.
  202.  *
  203.  * We keep the free list sorted by address so that coalescing is
  204.  * trivial.
  205.  *
  206.  * XXX
  207.  * Probably worth profiling this to see how expensive it is.
  208.  */
  209. hp = (struct __head *)regionp;
  210. for (elp = SH_LIST_FIRST(hp, __data), lastp = NULL;
  211.     elp != NULL && (void *)elp < (void *)ptr;
  212.     lastp = elp, elp = SH_LIST_NEXT(elp, links, __data))
  213. ;
  214. /*
  215.  * Elp is either NULL (we reached the end of the list), or the slot
  216.  * after the one that's being returned.  Lastp is either NULL (we're
  217.  * returning the first element of the list) or the element before the
  218.  * one being returned.
  219.  *
  220.  * Check for coalescing with the next element.
  221.  */
  222. merged = 0;
  223. if ((u_int8_t *)ptr + free_size == (u_int8_t *)elp) {
  224. newp->len += elp->len + sizeof(size_t);
  225. SH_LIST_REMOVE(elp, links, __data);
  226. if (lastp != NULL)
  227. SH_LIST_INSERT_AFTER(lastp, newp, links, __data);
  228. else
  229. SH_LIST_INSERT_HEAD(hp, newp, links, __data);
  230. merged = 1;
  231. }
  232. /* Check for coalescing with the previous element. */
  233. if (lastp != NULL && (u_int8_t *)lastp +
  234.     lastp->len + sizeof(size_t) == (u_int8_t *)newp) {
  235. lastp->len += newp->len + sizeof(size_t);
  236. /*
  237.  * If we have already put the new element into the list take
  238.  * it back off again because it's just been merged with the
  239.  * previous element.
  240.  */
  241. if (merged)
  242. SH_LIST_REMOVE(newp, links, __data);
  243. merged = 1;
  244. }
  245. if (!merged) {
  246. if (lastp == NULL)
  247. SH_LIST_INSERT_HEAD(hp, newp, links, __data);
  248. else
  249. SH_LIST_INSERT_AFTER(lastp, newp, links, __data);
  250. }
  251. }
  252. /*
  253.  * __db_shalloc_count --
  254.  * Return the amount of memory on the free list.
  255.  *
  256.  * PUBLIC: size_t __db_shalloc_count __P((void *));
  257.  */
  258. size_t
  259. __db_shalloc_count(addr)
  260. void *addr;
  261. {
  262. struct __data *elp;
  263. size_t count;
  264. count = 0;
  265. for (elp = SH_LIST_FIRST((struct __head *)addr, __data);
  266.     elp != NULL;
  267.     elp = SH_LIST_NEXT(elp, links, __data))
  268. count += elp->len;
  269. return (count);
  270. }
  271. /*
  272.  * __db_shsizeof --
  273.  * Return the size of a shalloc'd piece of memory.
  274.  *
  275.  * !!!
  276.  * Note that this is from an internal standpoint -- it includes not only
  277.  * the size of the memory being used, but also the extra alignment bytes
  278.  * in front and, #ifdef DIAGNOSTIC, the guard byte at the end.
  279.  *
  280.  * PUBLIC: size_t __db_shsizeof __P((void *));
  281.  */
  282. size_t
  283. __db_shsizeof(ptr)
  284. void *ptr;
  285. {
  286. struct __data *elp;
  287. size_t *sp;
  288. /*
  289.  * Step back over flagged length fields to find the beginning of
  290.  * the object and its real size.
  291.  */
  292. for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp)
  293. ;
  294. elp = (struct __data *)((u_int8_t *)sp - sizeof(size_t));
  295. return (elp->len);
  296. }
  297. /*
  298.  * __db_shalloc_dump --
  299.  *
  300.  * PUBLIC: void __db_shalloc_dump __P((void *, FILE *));
  301.  */
  302. void
  303. __db_shalloc_dump(addr, fp)
  304. void *addr;
  305. FILE *fp;
  306. {
  307. struct __data *elp;
  308. /* Make it easy to call from the debugger. */
  309. if (fp == NULL)
  310. fp = stderr;
  311. fprintf(fp, "%snMemory free listn", DB_LINE);
  312. for (elp = SH_LIST_FIRST((struct __head *)addr, __data);
  313.     elp != NULL;
  314.     elp = SH_LIST_NEXT(elp, links, __data))
  315. fprintf(fp, "%#lx: %lut", (u_long)elp, (u_long)elp->len);
  316. fprintf(fp, "n");
  317. }