X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/33a9da85867c540b95d99573defe39b47c5f6f45..ea39fd08c260e7faa92334952d4acd37e3892b6c:/src/xbt/mmalloc/mrealloc.c diff --git a/src/xbt/mmalloc/mrealloc.c b/src/xbt/mmalloc/mrealloc.c index e2004aaf47..b9deaffdde 100644 --- a/src/xbt/mmalloc/mrealloc.c +++ b/src/xbt/mmalloc/mrealloc.c @@ -1,26 +1,15 @@ /* Change the size of a block allocated by `mmalloc'. Copyright 1990, 1991 Free Software Foundation - Written May 1989 by Mike Haertel. + Written May 1989 by Mike Haertel. */ -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. 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. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#include /* Prototypes for memcpy, memmove, memset, etc */ +#include /* Prototypes for memcpy, memmove, memset, etc */ +#include /* abort */ #include "mmprivate.h" @@ -31,133 +20,128 @@ Boston, MA 02111-1307, USA. new region. This module has incestuous knowledge of the internals of both mfree and mmalloc. */ -PTR -mrealloc (md, ptr, size) - PTR md; - PTR ptr; - size_t size; +void *mrealloc(xbt_mheap_t mdp, void *ptr, size_t size) { - struct mdesc *mdp; - PTR result; + void *result; int type; size_t block, blocks, oldlimit; - if (size == 0) - { - mfree (md, ptr); - return (mmalloc (md, 0)); - } - else if (ptr == NULL) - { - return (mmalloc (md, size)); + /* Only keep real realloc, and reroute hidden malloc and free to the relevant functions */ + if (size == 0) { + mfree(mdp, ptr); + return mmalloc(mdp, 0); + } else if (ptr == NULL) { + return mmalloc(mdp, size); + } + + //printf("(%s)realloc %p to %d...",xbt_thread_self_name(),ptr,(int)size); + + if ((char *) ptr < (char *) mdp->heapbase || BLOCK(ptr) > mdp->heapsize) { + printf + ("FIXME. Ouch, this pointer is not mine, refusing to proceed (another solution would be to malloc it instead of reallocing it, see source code)\n"); + result = mmalloc(mdp, size); + abort(); + return result; + } + + size_t requested_size = size; // The amount of memory requested by user, for real + + /* Work even if the user was stupid enough to ask a ridicullously small block (even 0-length), + * ie return a valid block that can be realloced and freed. + * glibc malloc does not use this trick but return a constant pointer, but we need to enlist the free fragments later on. + */ + if (size < SMALLEST_POSSIBLE_MALLOC) + size = SMALLEST_POSSIBLE_MALLOC; + + block = BLOCK(ptr); + + type = mdp->heapinfo[block].type; + + switch (type) { + case -1: + fprintf(stderr, "Asked realloc a fragment coming from a *free* block. I'm puzzled.\n"); + abort(); + break; + + case 0: + /* Maybe reallocate a large block to a small fragment. */ + + if (size <= BLOCKSIZE / 2) { // Full block -> Fragment; no need to optimize for time + + result = mmalloc(mdp, size); + if (result != NULL) { // useless (mmalloc never returns NULL), but harmless + memcpy(result, ptr, requested_size); + mfree(mdp, ptr); + return (result); + } } - mdp = MD_TO_MDP (md); - - if (mdp -> mrealloc_hook != NULL) - { - return ((*mdp -> mrealloc_hook) (md, ptr, size)); + /* Full blocks -> Full blocks; see if we can hold it in place. */ + blocks = BLOCKIFY(size); + if (blocks < mdp->heapinfo[block].busy_block.size) { + int it; + /* The new size is smaller; return excess memory to the free list. */ + //printf("(%s) return excess memory...",xbt_thread_self_name()); + for (it= block+blocks; it< mdp->heapinfo[block].busy_block.size ; it++) + mdp->heapinfo[it].type = 0; // FIXME that should be useless, type should already be 0 here + + mdp->heapinfo[block + blocks].busy_block.size + = mdp->heapinfo[block].busy_block.size - blocks; + mfree(mdp, ADDRESS(block + blocks)); + + mdp->heapinfo[block].busy_block.size = blocks; + mdp->heapinfo[block].busy_block.busy_size = requested_size; + + result = ptr; + } else if (blocks == mdp->heapinfo[block].busy_block.size) { + + /* No block size change necessary; only update the requested size */ + result = ptr; + mdp->heapinfo[block].busy_block.busy_size = requested_size; + + } else { + /* Won't fit, so allocate a new region that will. + Free the old region first in case there is sufficient adjacent free space to grow without moving. + This trick mandates using a specific version of mmalloc that does not memset the memory to 0 after + action for obvious reasons. */ + blocks = mdp->heapinfo[block].busy_block.size; + /* Prevent free from actually returning memory to the system. */ + oldlimit = mdp->heaplimit; + mdp->heaplimit = 0; + mfree(mdp, ptr); + mdp->heaplimit = oldlimit; + + result = mmalloc_no_memset(mdp, requested_size); + //fprintf(stderr,"remalloc(%zu)~>%p\n",requested_size,result); + + if (ptr != result) + memmove(result, ptr, blocks * BLOCKSIZE); + /* FIXME: we should memset the end of the recently area */ } + break; - block = BLOCK (ptr); - - type = mdp -> heapinfo[block].busy.type; - switch (type) - { - case 0: - /* Maybe reallocate a large block to a small fragment. */ - if (size <= BLOCKSIZE / 2) - { - result = mmalloc (md, size); - if (result != NULL) - { - memcpy (result, ptr, size); - mfree (md, ptr); - return (result); - } - } - - /* The new size is a large allocation as well; - see if we can hold it in place. */ - blocks = BLOCKIFY (size); - if (blocks < mdp -> heapinfo[block].busy.info.size) - { - /* The new size is smaller; return excess memory to the free list. */ - mdp -> heapinfo[block + blocks].busy.type = 0; - mdp -> heapinfo[block + blocks].busy.info.size - = mdp -> heapinfo[block].busy.info.size - blocks; - mdp -> heapinfo[block].busy.info.size = blocks; - mfree (md, ADDRESS (block + blocks)); - result = ptr; - } - else if (blocks == mdp -> heapinfo[block].busy.info.size) - { - /* No size change necessary. */ - result = ptr; - } - else - { - /* Won't fit, so allocate a new region that will. - Free the old region first in case there is sufficient - adjacent free space to grow without moving. */ - blocks = mdp -> heapinfo[block].busy.info.size; - /* Prevent free from actually returning memory to the system. */ - oldlimit = mdp -> heaplimit; - mdp -> heaplimit = 0; - mfree (md, ptr); - mdp -> heaplimit = oldlimit; - result = mmalloc (md, size); - if (result == NULL) - { - mmalloc (md, blocks * BLOCKSIZE); - return (NULL); - } - if (ptr != result) - { - memmove (result, ptr, blocks * BLOCKSIZE); - } - } - break; - - default: - /* Old size is a fragment; type is logarithm - to base two of the fragment size. */ - if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) - { - /* The new size is the same kind of fragment. */ - result = ptr; - } - else - { - /* The new size is different; allocate a new space, - and copy the lesser of the new size and the old. */ - result = mmalloc (md, size); - if (result == NULL) - { - return (NULL); - } - memcpy (result, ptr, MIN (size, (size_t) 1 << type)); - mfree (md, ptr); - } - break; - } + default: /* Fragment -> ??; type=logarithm to base two of the fragment size. */ - return (result); -} + if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) { + /* The new size is the same kind of fragment. */ + //printf("(%s) new size is same kind of fragment...",xbt_thread_self_name()); -/* 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). */ + result = ptr; + int frag_nb = RESIDUAL(result, BLOCKSIZE) >> type; + mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = requested_size; -PTR -realloc (ptr, size) - PTR ptr; - size_t size; -{ - PTR result; + } else { /* fragment -> Either other fragment, or block */ + /* The new size is different; allocate a new space, + and copy the lesser of the new size and the old. */ + //printf("(%s) new size is different...",xbt_thread_self_name()); - result = mrealloc ((PTR) NULL, ptr, size); + result = mmalloc(mdp, requested_size); + + memcpy(result, ptr, MIN(requested_size, (size_t) 1 << type)); + mfree(mdp, ptr); + } + break; + } + //printf("(%s) Done reallocing: %p\n",xbt_thread_self_name(),result);fflush(stdout); return (result); }