heap_free.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * libc/stdlib/malloc-zarg/heap_free.c -- return memory to a heap
  3. *
  4. * Copyright (C) 2002 NEC Corporation
  5. * Copyright (C) 2002 Miles Bader <miles@gnu.org>
  6. *
  7. * This file is subject to the terms and conditions of the GNU Lesser
  8. * General Public License. See the file COPYING.LIB in the main
  9. * directory of this archive for more details.
  10. *
  11. * Written by Miles Bader <miles@gnu.org>
  12. */
  13. #include <stdlib.h>
  14. #include "heap.h"
  15. /* Return the memory area MEM of size SIZE to HEAP. */
  16. void
  17. __heap_free (struct heap *heap, void *mem, size_t size)
  18. {
  19. struct heap_free_area *prev_fa, *fa, *new_fa;
  20. void *end = (char *)mem + size;
  21. mutex_lock (heap->lock);
  22. HEAP_DEBUG (heap, "before __heap_free");
  23. /* Find an adjacent free-list entry. */
  24. for (prev_fa = 0, fa = heap->free_areas; fa; prev_fa = fa, fa = fa->next)
  25. {
  26. size_t fa_size = fa->size;
  27. void *fa_end = HEAP_FREE_AREA_END (fa);
  28. void *fa_mem = HEAP_FREE_AREA_START (fa);
  29. if (fa_mem == end)
  30. /* FA is just after MEM, grow down to encompass it. */
  31. {
  32. fa_size += size;
  33. /* See if FA can now be merged with its predecessor. */
  34. if (prev_fa && fa_mem - size == HEAP_FREE_AREA_END (prev_fa))
  35. /* Yup; merge PREV_FA's info into FA. */
  36. {
  37. struct heap_free_area *pp = prev_fa->prev;
  38. fa_size += prev_fa->size;
  39. if (pp)
  40. pp->next = fa;
  41. else
  42. heap->free_areas = fa;
  43. fa->prev = pp;
  44. }
  45. fa->size = fa_size;
  46. goto done;
  47. }
  48. else if (fa_end == mem)
  49. /* FA is just before MEM, expand to encompass it. */
  50. {
  51. struct heap_free_area *next_fa = fa->next;
  52. fa_size += size;
  53. /* See if FA can now be merged with its successor. */
  54. if (next_fa && fa_end + size == HEAP_FREE_AREA_START (next_fa))
  55. {
  56. /* Yup; merge FA's info into NEXT_FA. */
  57. fa_size += next_fa->size;
  58. if (prev_fa)
  59. prev_fa->next = next_fa;
  60. else
  61. heap->free_areas = next_fa;
  62. next_fa->prev = prev_fa;
  63. fa = next_fa;
  64. }
  65. else
  66. /* FA can't be merged; move the descriptor for it to the tail-end
  67. of the memory block. */
  68. {
  69. new_fa = (struct heap_free_area *)((char *)fa + size);
  70. /* Update surrounding free-areas to point to FA's new address. */
  71. if (prev_fa)
  72. prev_fa->next = new_fa;
  73. else
  74. heap->free_areas = new_fa;
  75. if (next_fa)
  76. next_fa->prev = new_fa;
  77. /* Fill in the moved descriptor. */
  78. new_fa->prev = prev_fa;
  79. new_fa->next = next_fa;
  80. fa = new_fa;
  81. }
  82. fa->size = fa_size;
  83. goto done;
  84. }
  85. else if (fa_mem > mem)
  86. /* We've reached the right spot in the free-list without finding an
  87. adjacent free-area, so add a new free area to hold MEM. */
  88. break;
  89. }
  90. /* Make a new free-list entry. */
  91. /* NEW_FA initially holds only MEM. */
  92. new_fa = (struct heap_free_area *)
  93. ((char *)mem + size - sizeof (struct heap_free_area));
  94. new_fa->size = size;
  95. new_fa->next = fa;
  96. new_fa->prev = prev_fa;
  97. /* Insert NEW_FA in the free-list between PREV_FA and FA. */
  98. if (prev_fa)
  99. prev_fa->next = new_fa;
  100. else
  101. heap->free_areas = new_fa;
  102. if (fa)
  103. fa->prev = new_fa;
  104. done:
  105. HEAP_DEBUG (heap, "after __heap_free");
  106. mutex_unlock (heap->lock);
  107. }