diff options
Diffstat (limited to 'libc/stdlib/malloc-930716/free.c')
-rw-r--r-- | libc/stdlib/malloc-930716/free.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/libc/stdlib/malloc-930716/free.c b/libc/stdlib/malloc-930716/free.c new file mode 100644 index 000000000..fbc98b714 --- /dev/null +++ b/libc/stdlib/malloc-930716/free.c @@ -0,0 +1,156 @@ +/* free.c - C standard library routine. + Copyright (c) 1989, 1993 Michael J. Haertel + You may redistribute this library under the terms of the + GNU Library General Public License (version 2 or any later + version) as published by the Free Software Foundation. + THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED + WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR + WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include "malloc.h" + +/* Return memory to the heap. */ +void +_free_internal (void *ptr) +{ + int block, blocks, i, type; + struct list *prev, *next; + + if (!ptr) + return; + + block = BLOCK(ptr); + + switch (type = _heapinfo[block].busy.type) { + case 0: + /* Find the free cluster previous to this one in the free list. + Start searching at the last block referenced; this may benefit + programs with locality of allocation. */ + i = _heapindex; + if (i > block) + while (i > block) + i = _heapinfo[i].free.prev; + else { + do + i = _heapinfo[i].free.next; + while (i > 0 && i < block); + i = _heapinfo[i].free.prev; + } + + /* Determine how to link this block into the free list. */ + if (block == i + _heapinfo[i].free.size) { + /* Coalesce this block with its predecessor. */ + _heapinfo[i].free.size += _heapinfo[block].busy.info.size; + block = i; + } else { + /* Really link this block back into the free list. */ + _heapinfo[block].free.size = _heapinfo[block].busy.info.size; + _heapinfo[block].free.next = _heapinfo[i].free.next; + _heapinfo[block].free.prev = i; + _heapinfo[i].free.next = block; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + } + + /* Now that the block is linked in, see if we can coalesce it + with its successor (by deleting its successor from the list + and adding in its size). */ + if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) { + _heapinfo[block].free.size + += _heapinfo[_heapinfo[block].free.next].free.size; + _heapinfo[block].free.next + = _heapinfo[_heapinfo[block].free.next].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev = block; + } + + /* Now see if we can return stuff to the system. */ + blocks = _heapinfo[block].free.size; + if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit + && (*__morecore)(0) == ADDRESS(block + blocks)) { + _heaplimit -= blocks; + (*__morecore)(-blocks * BLOCKSIZE); + _heapinfo[_heapinfo[block].free.prev].free.next + = _heapinfo[block].free.next; + _heapinfo[_heapinfo[block].free.next].free.prev + = _heapinfo[block].free.prev; + block = _heapinfo[block].free.prev; + } + + /* Set the next search to begin at this block. */ + _heapindex = block; + break; + + default: + /* Get the address of the first free fragment in this block. */ + prev = (struct list *) ((char *) ADDRESS(block) + + (_heapinfo[block].busy.info.frag.first + << type)); + + if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 + && _fragblocks[type] > 1) { + /* If all fragments of this block are free, remove them + from the fragment list and free the whole block. */ + --_fragblocks[type]; + for (next = prev, i = 1; i < BLOCKSIZE >> type; ++i) + next = next->next; + prev->prev->next = next; + if (next) + next->prev = prev->prev; + _heapinfo[block].busy.type = 0; + _heapinfo[block].busy.info.size = 1; + free(ADDRESS(block)); + } else if (_heapinfo[block].busy.info.frag.nfree) { + /* If some fragments of this block are free, link this fragment + into the fragment list after the first free fragment of + this block. */ + next = ptr; + next->next = prev->next; + next->prev = prev; + prev->next = next; + if (next->next) + next->next->prev = next; + ++_heapinfo[block].busy.info.frag.nfree; + } else { + /* No fragments of this block are free, so link this fragment + into the fragment list and announce that it is the first + free fragment of this block. */ + prev = (struct list *) ptr; + _heapinfo[block].busy.info.frag.nfree = 1; + _heapinfo[block].busy.info.frag.first + = (unsigned int) ((char *) ptr - (char *) NULL) % BLOCKSIZE + >> type; + prev->next = _fraghead[type].next; + prev->prev = &_fraghead[type]; + prev->prev->next = prev; + if (prev->next) + prev->next->prev = prev; + } + break; + } +} + +struct alignlist *_aligned_blocks = NULL; + +void +free (void *ptr) +{ + register struct alignlist *l; + + if (ptr == NULL) + return; + + for (l = _aligned_blocks; l != NULL; l = l->next) + { + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + } + + _free_internal (ptr); +} |