1 1.1 christos /* $NetBSD: free.c,v 1.1.1.1 2016/01/13 21:42:18 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* Free a block of memory allocated by `malloc'. 4 1.1 christos Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc. 5 1.1 christos Written May 1989 by Mike Haertel. 6 1.1 christos 7 1.1 christos This library is free software; you can redistribute it and/or 8 1.1 christos modify it under the terms of the GNU Library General Public License as 9 1.1 christos published by the Free Software Foundation; either version 2 of the 10 1.1 christos License, or (at your option) any later version. 11 1.1 christos 12 1.1 christos This library is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 1.1 christos Library General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU Library General Public 18 1.1 christos License along with this library; see the file COPYING.LIB. If 19 1.1 christos not, write to the Free Software Foundation, Inc., 675 Mass Ave, 20 1.1 christos Cambridge, MA 02139, USA. 21 1.1 christos 22 1.1 christos The author may be reached (Email) at the address mike (at) ai.mit.edu, 23 1.1 christos or (US mail) as Mike Haertel c/o Free Software Foundation. */ 24 1.1 christos 25 1.1 christos #ifndef _MALLOC_INTERNAL 26 1.1 christos #define _MALLOC_INTERNAL 27 1.1 christos #include <malloc.h> 28 1.1 christos #endif 29 1.1 christos 30 1.1 christos /* Debugging hook for free. */ 31 1.1 christos void (*__free_hook) __P ((__ptr_t __ptr)); 32 1.1 christos 33 1.1 christos /* List of blocks allocated by memalign. */ 34 1.1 christos struct alignlist *_aligned_blocks = NULL; 35 1.1 christos 36 1.1 christos /* Return memory to the heap. 37 1.1 christos Like `free' but don't call a __free_hook if there is one. */ 38 1.1 christos void 39 1.1 christos _free_internal (ptr) 40 1.1 christos __ptr_t ptr; 41 1.1 christos { 42 1.1 christos int type; 43 1.1 christos __malloc_size_t block, blocks; 44 1.1 christos register __malloc_size_t i; 45 1.1 christos struct list *prev, *next; 46 1.1 christos 47 1.1 christos block = BLOCK (ptr); 48 1.1 christos 49 1.1 christos type = _heapinfo[block].busy.type; 50 1.1 christos switch (type) 51 1.1 christos { 52 1.1 christos case 0: 53 1.1 christos /* Get as many statistics as early as we can. */ 54 1.1 christos --_chunks_used; 55 1.1 christos _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; 56 1.1 christos _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; 57 1.1 christos 58 1.1 christos /* Find the free cluster previous to this one in the free list. 59 1.1 christos Start searching at the last block referenced; this may benefit 60 1.1 christos programs with locality of allocation. */ 61 1.1 christos i = _heapindex; 62 1.1 christos if (i > block) 63 1.1 christos while (i > block) 64 1.1 christos i = _heapinfo[i].free.prev; 65 1.1 christos else 66 1.1 christos { 67 1.1 christos do 68 1.1 christos i = _heapinfo[i].free.next; 69 1.1 christos while (i > 0 && i < block); 70 1.1 christos i = _heapinfo[i].free.prev; 71 1.1 christos } 72 1.1 christos 73 1.1 christos /* Determine how to link this block into the free list. */ 74 1.1 christos if (block == i + _heapinfo[i].free.size) 75 1.1 christos { 76 1.1 christos /* Coalesce this block with its predecessor. */ 77 1.1 christos _heapinfo[i].free.size += _heapinfo[block].busy.info.size; 78 1.1 christos block = i; 79 1.1 christos } 80 1.1 christos else 81 1.1 christos { 82 1.1 christos /* Really link this block back into the free list. */ 83 1.1 christos _heapinfo[block].free.size = _heapinfo[block].busy.info.size; 84 1.1 christos _heapinfo[block].free.next = _heapinfo[i].free.next; 85 1.1 christos _heapinfo[block].free.prev = i; 86 1.1 christos _heapinfo[i].free.next = block; 87 1.1 christos _heapinfo[_heapinfo[block].free.next].free.prev = block; 88 1.1 christos ++_chunks_free; 89 1.1 christos } 90 1.1 christos 91 1.1 christos /* Now that the block is linked in, see if we can coalesce it 92 1.1 christos with its successor (by deleting its successor from the list 93 1.1 christos and adding in its size). */ 94 1.1 christos if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) 95 1.1 christos { 96 1.1 christos _heapinfo[block].free.size 97 1.1 christos += _heapinfo[_heapinfo[block].free.next].free.size; 98 1.1 christos _heapinfo[block].free.next 99 1.1 christos = _heapinfo[_heapinfo[block].free.next].free.next; 100 1.1 christos _heapinfo[_heapinfo[block].free.next].free.prev = block; 101 1.1 christos --_chunks_free; 102 1.1 christos } 103 1.1 christos 104 1.1 christos /* Now see if we can return stuff to the system. */ 105 1.1 christos blocks = _heapinfo[block].free.size; 106 1.1 christos if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit 107 1.1 christos && (*__morecore) (0) == ADDRESS (block + blocks)) 108 1.1 christos { 109 1.1 christos register __malloc_size_t bytes = blocks * BLOCKSIZE; 110 1.1 christos _heaplimit -= blocks; 111 1.1 christos (*__morecore) (-bytes); 112 1.1 christos _heapinfo[_heapinfo[block].free.prev].free.next 113 1.1 christos = _heapinfo[block].free.next; 114 1.1 christos _heapinfo[_heapinfo[block].free.next].free.prev 115 1.1 christos = _heapinfo[block].free.prev; 116 1.1 christos block = _heapinfo[block].free.prev; 117 1.1 christos --_chunks_free; 118 1.1 christos _bytes_free -= bytes; 119 1.1 christos } 120 1.1 christos 121 1.1 christos /* Set the next search to begin at this block. */ 122 1.1 christos _heapindex = block; 123 1.1 christos break; 124 1.1 christos 125 1.1 christos default: 126 1.1 christos /* Do some of the statistics. */ 127 1.1 christos --_chunks_used; 128 1.1 christos _bytes_used -= 1 << type; 129 1.1 christos ++_chunks_free; 130 1.1 christos _bytes_free += 1 << type; 131 1.1 christos 132 1.1 christos /* Get the address of the first free fragment in this block. */ 133 1.1 christos prev = (struct list *) ((char *) ADDRESS (block) + 134 1.1 christos (_heapinfo[block].busy.info.frag.first << type)); 135 1.1 christos 136 1.1 christos if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) 137 1.1 christos { 138 1.1 christos /* If all fragments of this block are free, remove them 139 1.1 christos from the fragment list and free the whole block. */ 140 1.1 christos next = prev; 141 1.1 christos for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) 142 1.1 christos next = next->next; 143 1.1 christos prev->prev->next = next; 144 1.1 christos if (next != NULL) 145 1.1 christos next->prev = prev->prev; 146 1.1 christos _heapinfo[block].busy.type = 0; 147 1.1 christos _heapinfo[block].busy.info.size = 1; 148 1.1 christos 149 1.1 christos /* Keep the statistics accurate. */ 150 1.1 christos ++_chunks_used; 151 1.1 christos _bytes_used += BLOCKSIZE; 152 1.1 christos _chunks_free -= BLOCKSIZE >> type; 153 1.1 christos _bytes_free -= BLOCKSIZE; 154 1.1 christos 155 1.1 christos free (ADDRESS (block)); 156 1.1 christos } 157 1.1 christos else if (_heapinfo[block].busy.info.frag.nfree != 0) 158 1.1 christos { 159 1.1 christos /* If some fragments of this block are free, link this 160 1.1 christos fragment into the fragment list after the first free 161 1.1 christos fragment of this block. */ 162 1.1 christos next = (struct list *) ptr; 163 1.1 christos next->next = prev->next; 164 1.1 christos next->prev = prev; 165 1.1 christos prev->next = next; 166 1.1 christos if (next->next != NULL) 167 1.1 christos next->next->prev = next; 168 1.1 christos ++_heapinfo[block].busy.info.frag.nfree; 169 1.1 christos } 170 1.1 christos else 171 1.1 christos { 172 1.1 christos /* No fragments of this block are free, so link this 173 1.1 christos fragment into the fragment list and announce that 174 1.1 christos it is the first free fragment of this block. */ 175 1.1 christos prev = (struct list *) ptr; 176 1.1 christos _heapinfo[block].busy.info.frag.nfree = 1; 177 1.1 christos _heapinfo[block].busy.info.frag.first = (unsigned long int) 178 1.1 christos ((unsigned long int) ((char *) ptr - (char *) NULL) 179 1.1 christos % BLOCKSIZE >> type); 180 1.1 christos prev->next = _fraghead[type].next; 181 1.1 christos prev->prev = &_fraghead[type]; 182 1.1 christos prev->prev->next = prev; 183 1.1 christos if (prev->next != NULL) 184 1.1 christos prev->next->prev = prev; 185 1.1 christos } 186 1.1 christos break; 187 1.1 christos } 188 1.1 christos } 189 1.1 christos 190 1.1 christos /* Return memory to the heap. */ 191 1.1 christos void 192 1.1 christos free (ptr) 193 1.1 christos __ptr_t ptr; 194 1.1 christos { 195 1.1 christos register struct alignlist *l; 196 1.1 christos 197 1.1 christos if (ptr == NULL) 198 1.1 christos return; 199 1.1 christos 200 1.1 christos for (l = _aligned_blocks; l != NULL; l = l->next) 201 1.1 christos if (l->aligned == ptr) 202 1.1 christos { 203 1.1 christos l->aligned = NULL; /* Mark the slot in the list as free. */ 204 1.1 christos ptr = l->exact; 205 1.1 christos break; 206 1.1 christos } 207 1.1 christos 208 1.1 christos if (__free_hook != NULL) 209 1.1 christos (*__free_hook) (ptr); 210 1.1 christos else 211 1.1 christos _free_internal (ptr); 212 1.1 christos } 213