1 /* Free a block of memory allocated by `mmalloc'.
2 Copyright 1990, 1991, 1992 Free Software Foundation
4 Written May 1989 by Mike Haertel.
5 Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) */
7 /* Copyright (c) 2010-2013. The SimGrid Team.
8 * All rights reserved. */
10 /* This program is free software; you can redistribute it and/or modify it
11 * under the terms of the license (GNU LGPL) which comes with this package. */
13 #include "mmprivate.h"
17 /* Return memory to the heap.
18 Like `mfree' but don't call a mfree_hook if there is one. */
20 /* Return memory to the heap. */
21 void mfree(struct mdesc *mdp, void *ptr)
24 size_t block, frag_nb;
28 mmalloc_paranoia(mdp);
29 // fprintf(stderr,"free(%p)\n",ptr);
36 if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
37 fprintf(stderr,"Ouch, this pointer is not mine. I refuse to free it. I refuse it to death!!\n");
41 type = mdp->heapinfo[block].type;
44 case -1: /* Already free */
46 THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled\n");
50 /* Get as many statistics as early as we can. */
51 mdp -> heapstats.chunks_used--;
52 mdp -> heapstats.bytes_used -=
53 mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
54 mdp -> heapstats.bytes_free +=
55 mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
58 if(mdp->heapinfo[block].busy_block.ignore > 0)
59 MC_remove_ignore_heap(ptr, mdp -> heapinfo[block].busy_block.busy_size);
62 /* Find the free cluster previous to this one in the free list.
63 Start searching at the last block referenced; this may benefit
64 programs with locality of allocation. */
68 i = mdp->heapinfo[i].free_block.prev;
72 i = mdp->heapinfo[i].free_block.next;
74 while ((i != 0) && (i < block));
75 i = mdp->heapinfo[i].free_block.prev;
78 /* Determine how to link this block into the free list. */
79 if (block == i + mdp->heapinfo[i].free_block.size) {
81 /* Coalesce this block with its predecessor. */
82 mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
83 /* Mark all my ex-blocks as free */
84 for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
85 if (mdp->heapinfo[block+it].type <0) {
86 fprintf(stderr,"Internal Error: Asked to free a block already marked as free (block=%lu it=%d type=%lu). Please report this bug.\n",
87 (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].type);
90 mdp->heapinfo[block+it].type = -1;
95 //fprintf(stderr,"Free block %d to %d (as a new chunck)\n",block,block+mdp->heapinfo[block].busy_block.size);
96 /* Really link this block back into the free list. */
97 mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
98 mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
99 mdp->heapinfo[block].free_block.prev = i;
100 mdp->heapinfo[i].free_block.next = block;
101 mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
102 mdp -> heapstats.chunks_free++;
103 /* Mark all my ex-blocks as free */
104 for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
105 if (mdp->heapinfo[block+it].type <0) {
106 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",
107 (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].free_block.size,(unsigned long)mdp->heapinfo[block].type);
110 mdp->heapinfo[block+it].type = -1;
114 /* Now that the block is linked in, see if we can coalesce it
115 with its successor (by deleting its successor from the list
116 and adding in its size). */
117 if (block + mdp->heapinfo[block].free_block.size ==
118 mdp->heapinfo[block].free_block.next) {
119 mdp->heapinfo[block].free_block.size
120 += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
121 mdp->heapinfo[block].free_block.next
122 = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
123 mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
124 mdp -> heapstats.chunks_free--;
127 /* Now see if we can return stuff to the system. */
128 /* blocks = mdp -> heapinfo[block].free.size;
129 if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
130 && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
132 register size_t bytes = blocks * BLOCKSIZE;
133 mdp -> heaplimit -= blocks;
134 mdp -> morecore (mdp, -bytes);
135 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
136 = mdp -> heapinfo[block].free.next;
137 mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
138 = mdp -> heapinfo[block].free.prev;
139 block = mdp -> heapinfo[block].free.prev;
140 mdp -> heapstats.chunks_free--;
141 mdp -> heapstats.bytes_free -= bytes;
144 /* Set the next search to begin at this block.
145 This is probably important to the trick where realloc returns the block to
146 the system before reasking for the same block with a bigger size. */
147 mdp->heapindex = block;
151 /* Do some of the statistics. */
152 mdp -> heapstats.chunks_used--;
153 mdp -> heapstats.bytes_used -= 1 << type;
154 mdp -> heapstats.chunks_free++;
155 mdp -> heapstats.bytes_free += 1 << type;
157 frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
159 if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
161 THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
165 if(mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
166 MC_remove_ignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
169 /* Set size used in the fragment to -1 */
170 mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
171 mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
173 // fprintf(stderr,"nfree:%zu capa:%d\n", mdp->heapinfo[block].busy_frag.nfree,(BLOCKSIZE >> type));
174 if (mdp->heapinfo[block].busy_frag.nfree ==
175 (BLOCKSIZE >> type) - 1) {
176 /* If all fragments of this block are free, remove this block from its swag and free the whole block. */
177 xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
179 /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
180 mdp->heapinfo[block].type = 0;
181 mdp->heapinfo[block].busy_block.size = 1;
182 mdp->heapinfo[block].busy_block.busy_size = 0;
184 /* Keep the statistics accurate. */
185 mdp -> heapstats.chunks_used++;
186 mdp -> heapstats.bytes_used += BLOCKSIZE;
187 mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
188 mdp -> heapstats.bytes_free -= BLOCKSIZE;
190 mfree((void *) mdp, (void *) ADDRESS(block));
191 } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
192 /* If some fragments of this block are free, you know what? I'm already happy. */
193 ++mdp->heapinfo[block].busy_frag.nfree;
195 /* No fragments of this block were free before the one we just released,
196 * so add this block to the swag and announce that
197 it is the first free fragment of this block. */
198 mdp->heapinfo[block].busy_frag.nfree = 1;
199 mdp->heapinfo[block].freehook.prev = NULL;
200 mdp->heapinfo[block].freehook.next = NULL;
202 xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);