-/* Free a block of memory allocated by `mmalloc'.
- Copyright 1990, 1991, 1992 Free Software Foundation
+/* Free a block of memory allocated by `mmalloc'. */
- Written May 1989 by Mike Haertel.
- Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com)
-
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+/* Copyright (c) 2010-2014. The SimGrid Team.
+ * All rights reserved. */
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Library General Public License for more details.
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+/* Copyright 1990, 1991, 1992 Free Software Foundation
- The author may be reached (Email) at the address mike@ai.mit.edu,
- or (US mail) as Mike Haertel c/o Free Software Foundation. */
+ Written May 1989 by Mike Haertel.
+ Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) */
#include "mmprivate.h"
+#include "xbt/ex.h"
+#include "mc/mc.h"
/* Return memory to the heap.
Like `mfree' but don't call a mfree_hook if there is one. */
-void
-__mmalloc_free (struct mdesc *mdp, void *ptr)
+/* Return memory to the heap. */
+void mfree(struct mdesc *mdp, void *ptr)
{
int type;
- size_t block;//, blocks; unused variable?
+ size_t block, frag_nb;
register size_t i;
- struct list *prev, *next;
-
- block = BLOCK (ptr);
-
- type = mdp -> heapinfo[block].busy.type;
- switch (type)
- {
- case 0:
- /* Get as many statistics as early as we can. */
- mdp -> heapstats.chunks_used--;
- mdp -> heapstats.bytes_used -=
- mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
- mdp -> heapstats.bytes_free +=
- mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
-
- /* 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 = mdp -> heapindex;
- if (i > block)
- {
- while (i > block)
- {
- i = mdp -> heapinfo[i].free.prev;
- }
- }
- else
- {
- do
- {
- i = mdp -> heapinfo[i].free.next;
- }
- while ((i != 0) && (i < block));
- i = mdp -> heapinfo[i].free.prev;
- }
-
- /* Determine how to link this block into the free list. */
- if (block == i + mdp -> heapinfo[i].free.size)
- {
- /* Coalesce this block with its predecessor. */
- mdp -> heapinfo[i].free.size +=
- mdp -> heapinfo[block].busy.info.size;
- block = i;
- }
- else
- {
- /* Really link this block back into the free list. */
- mdp -> heapinfo[block].free.size =
- mdp -> heapinfo[block].busy.info.size;
- mdp -> heapinfo[block].free.next = mdp -> heapinfo[i].free.next;
- mdp -> heapinfo[block].free.prev = i;
- mdp -> heapinfo[i].free.next = block;
- mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
- mdp -> heapstats.chunks_free++;
- }
-
- /* 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 + mdp -> heapinfo[block].free.size ==
- mdp -> heapinfo[block].free.next)
- {
- mdp -> heapinfo[block].free.size
- += mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.size;
- mdp -> heapinfo[block].free.next
- = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.next;
- mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
- mdp -> heapstats.chunks_free--;
- }
-
- /* Now see if we can return stuff to the system. */
- /* blocks = mdp -> heapinfo[block].free.size;
- if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
- && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
- {
- register size_t bytes = blocks * BLOCKSIZE;
- mdp -> heaplimit -= blocks;
- mdp -> morecore (mdp, -bytes);
- mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
- = mdp -> heapinfo[block].free.next;
- mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
- = mdp -> heapinfo[block].free.prev;
- block = mdp -> heapinfo[block].free.prev;
- mdp -> heapstats.chunks_free--;
- mdp -> heapstats.bytes_free -= bytes;
- }*/
-
- /* Set the next search to begin at this block. */
- mdp -> heapindex = block;
- break;
-
- default:
- /* Do some of the statistics. */
- mdp -> heapstats.chunks_used--;
- mdp -> heapstats.bytes_used -= 1 << type;
- mdp -> heapstats.chunks_free++;
- mdp -> heapstats.bytes_free += 1 << type;
-
- /* Get the address of the first free fragment in this block. */
- prev = (struct list *)
- ((char*) ADDRESS(block) +
- ( mdp -> heapinfo[block].busy.info.frag.first << type));
-
- if (mdp -> heapinfo[block].busy.info.frag.nfree ==
- (BLOCKSIZE >> type) - 1)
- {
- /* If all fragments of this block are free, remove them
- from the fragment list and free the whole block. */
- next = prev;
- for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
- {
- next = next -> next;
- }
- prev -> prev -> next = next;
- if (next != NULL)
- {
- next -> prev = prev -> prev;
- }
- mdp -> heapinfo[block].busy.type = 0;
- mdp -> heapinfo[block].busy.info.size = 1;
-
- /* Keep the statistics accurate. */
- mdp -> heapstats.chunks_used++;
- mdp -> heapstats.bytes_used += BLOCKSIZE;
- mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
- mdp -> heapstats.bytes_free -= BLOCKSIZE;
-
- mfree ((void*) mdp, (void*) ADDRESS(block));
- }
- else if (mdp -> heapinfo[block].busy.info.frag.nfree != 0)
- {
- /* If some fragments of this block are free, link this
- fragment into the fragment list after the first free
- fragment of this block. */
- next = (struct list *) ptr;
- next -> next = prev -> next;
- next -> prev = prev;
- prev -> next = next;
- if (next -> next != NULL)
- {
- next -> next -> prev = next;
- }
- ++mdp -> 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;
- mdp -> heapinfo[block].busy.info.frag.nfree = 1;
- mdp -> heapinfo[block].busy.info.frag.first =
- RESIDUAL (ptr, BLOCKSIZE) >> type;
- prev -> next = mdp -> fraghead[type].next;
- prev -> prev = &mdp -> fraghead[type];
- prev -> prev -> next = prev;
- if (prev -> next != NULL)
- {
- prev -> next -> prev = prev;
- }
- }
- break;
+ int it;
+
+ mmalloc_paranoia(mdp);
+// fprintf(stderr,"free(%p)\n",ptr);
+
+ if (ptr == NULL)
+ return;
+
+ block = BLOCK(ptr);
+
+ if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
+ fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
+ abort();
+ }
+
+ type = mdp->heapinfo[block].type;
+
+ switch (type) {
+ case -1: /* Already free */
+ UNLOCK(mdp);
+ THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled\n");
+ break;
+
+ case 0:
+ /* Get as many statistics as early as we can. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -=
+ mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
+ mdp -> heapstats.bytes_free +=
+ mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
+
+ if(MC_is_active()){
+ if(mdp->heapinfo[block].busy_block.ignore > 0)
+ MC_remove_ignore_heap(ptr, mdp -> heapinfo[block].busy_block.busy_size);
}
-}
-
-/* Return memory to the heap. */
-void
-mfree (void *md, void *ptr)
-{
- struct mdesc *mdp;
- register struct alignlist *l;
-
- if (ptr != NULL)
- {
- mdp = MD_TO_MDP (md);
- for (l = mdp -> 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;
- }
- }
- if (mdp -> mfree_hook != NULL)
- {
- (*mdp -> mfree_hook) (mdp, ptr);
- }
- else
- {
- __mmalloc_free (mdp, ptr);
- }
+ /* 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 = mdp->heapindex;
+ if (i > block) {
+ while (i > block) {
+ i = mdp->heapinfo[i].free_block.prev;
+ }
+ } else {
+ do {
+ i = mdp->heapinfo[i].free_block.next;
+ }
+ while ((i != 0) && (i < block));
+ i = mdp->heapinfo[i].free_block.prev;
}
-}
+ /* Determine how to link this block into the free list. */
+ if (block == i + mdp->heapinfo[i].free_block.size) {
+
+ /* Coalesce this block with its predecessor. */
+ mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
+ /* Mark all my ex-blocks as free */
+ for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
+ if (mdp->heapinfo[block+it].type <0) {
+ fprintf(stderr,"Internal Error: Asked to free a block already marked as free (block=%lu it=%d type=%lu). Please report this bug.\n",
+ (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].type);
+ abort();
+ }
+ mdp->heapinfo[block+it].type = -1;
+ }
+
+ block = i;
+ } else {
+ //fprintf(stderr,"Free block %d to %d (as a new chunck)\n",block,block+mdp->heapinfo[block].busy_block.size);
+ /* Really link this block back into the free list. */
+ mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
+ mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
+ mdp->heapinfo[block].free_block.prev = i;
+ mdp->heapinfo[i].free_block.next = block;
+ mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
+ mdp -> heapstats.chunks_free++;
+ /* Mark all my ex-blocks as free */
+ for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
+ if (mdp->heapinfo[block+it].type <0) {
+ fprintf(stderr,"Internal error: Asked to free a block already marked as free (block=%lu it=%d/%lu type=%lu). Please report this bug.\n",
+ (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].free_block.size,(unsigned long)mdp->heapinfo[block].type);
+ abort();
+ }
+ mdp->heapinfo[block+it].type = -1;
+ }
+ }
-/* Useless prototype to make gcc happy */
-void free(void* ptr);
+ /* 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 + mdp->heapinfo[block].free_block.size ==
+ mdp->heapinfo[block].free_block.next) {
+ mdp->heapinfo[block].free_block.size
+ += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
+ mdp->heapinfo[block].free_block.next
+ = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
+ mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
+ mdp -> heapstats.chunks_free--;
+ }
+ /* Now see if we can return stuff to the system. */
+ /* blocks = mdp -> heapinfo[block].free.size;
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
+ && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ mdp -> heaplimit -= blocks;
+ mdp -> morecore (mdp, -bytes);
+ mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+ = mdp -> heapinfo[block].free.next;
+ mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+ = mdp -> heapinfo[block].free.prev;
+ block = mdp -> heapinfo[block].free.prev;
+ mdp -> heapstats.chunks_free--;
+ mdp -> heapstats.bytes_free -= bytes;
+ } */
+
+ /* Set the next search to begin at this block.
+ This is probably important to the trick where realloc returns the block to
+ the system before reasking for the same block with a bigger size. */
+ mdp->heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ mdp -> heapstats.chunks_used--;
+ mdp -> heapstats.bytes_used -= 1 << type;
+ mdp -> heapstats.chunks_free++;
+ mdp -> heapstats.bytes_free += 1 << type;
+
+ frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
+
+ if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
+ UNLOCK(mdp);
+ THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
+ }
-/* When using this package, provide a version of malloc/realloc/free built
- on top of it, so that if we use the default sbrk() region we will not
- collide with another malloc package trying to do the same thing, if
- the application contains any "hidden" calls to malloc/realloc/free (such
- as inside a system library). */
+ if(MC_is_active()){
+ if(mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
+ MC_remove_ignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
+ }
-void
-free (void* ptr)
-{
- mfree ((void*) NULL, ptr);
+ /* Set size used in the fragment to -1 */
+ mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
+ mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
+
+// fprintf(stderr,"nfree:%zu capa:%d\n", mdp->heapinfo[block].busy_frag.nfree,(BLOCKSIZE >> type));
+ if (mdp->heapinfo[block].busy_frag.nfree ==
+ (BLOCKSIZE >> type) - 1) {
+ /* If all fragments of this block are free, remove this block from its swag and free the whole block. */
+ xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
+
+ /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
+ mdp->heapinfo[block].type = 0;
+ mdp->heapinfo[block].busy_block.size = 1;
+ mdp->heapinfo[block].busy_block.busy_size = 0;
+
+ /* Keep the statistics accurate. */
+ mdp -> heapstats.chunks_used++;
+ mdp -> heapstats.bytes_used += BLOCKSIZE;
+ mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
+ mdp -> heapstats.bytes_free -= BLOCKSIZE;
+
+ mfree((void *) mdp, (void *) ADDRESS(block));
+ } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
+ /* If some fragments of this block are free, you know what? I'm already happy. */
+ ++mdp->heapinfo[block].busy_frag.nfree;
+ } else {
+ /* No fragments of this block were free before the one we just released,
+ * so add this block to the swag and announce that
+ it is the first free fragment of this block. */
+ mdp->heapinfo[block].busy_frag.nfree = 1;
+ mdp->heapinfo[block].freehook.prev = NULL;
+ mdp->heapinfo[block].freehook.next = NULL;
+
+ xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
+ }
+ break;
+ }
}
+