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); +}  | 
