1 /* Free a block of memory allocated by `mmalloc'. */
3 /* Copyright (c) 2010-2015. The SimGrid Team.
4 * All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
9 /* Copyright 1990, 1991, 1992 Free Software Foundation
11 Written May 1989 by Mike Haertel.
12 Heavily modified Mar 1992 by Fred Fish. (fnf@cygnus.com) */
14 #include "mmprivate.h"
18 /* Return memory to the heap.
19 Like `mfree' but don't call a mfree_hook if there is one. */
21 /* Return memory to the heap. */
22 void mfree(struct mdesc *mdp, void *ptr)
25 size_t block, frag_nb;
29 mmalloc_paranoia(mdp);
30 // fprintf(stderr,"free(%p)\n",ptr);
37 if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
38 fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
42 type = mdp->heapinfo[block].type;
45 case MMALLOC_TYPE_HEAPINFO:
47 THROWF(system_error, 0, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
50 case MMALLOC_TYPE_FREE: /* Already free */
52 THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
55 case MMALLOC_TYPE_UNFRAGMENTED:
56 /* Get as many statistics as early as we can. */
57 mdp -> heapstats.chunks_used--;
58 mdp -> heapstats.bytes_used -=
59 mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
60 mdp -> heapstats.bytes_free +=
61 mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
64 if(mdp->heapinfo[block].busy_block.ignore > 0)
65 MC_remove_ignore_heap(ptr, mdp -> heapinfo[block].busy_block.busy_size);
68 /* Find the free cluster previous to this one in the free list.
69 Start searching at the last block referenced; this may benefit
70 programs with locality of allocation. */
74 i = mdp->heapinfo[i].free_block.prev;
78 i = mdp->heapinfo[i].free_block.next;
80 while ((i != 0) && (i < block));
81 i = mdp->heapinfo[i].free_block.prev;
84 /* Determine how to link this block into the free list. */
85 if (block == i + mdp->heapinfo[i].free_block.size) {
87 /* Coalesce this block with its predecessor. */
88 mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
89 /* Mark all my ex-blocks as free */
90 for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
91 if (mdp->heapinfo[block+it].type < 0) {
92 fprintf(stderr,"Internal Error: Asked to free a block already marked as free (block=%lu it=%d type=%lu). Please report this bug.\n",
93 (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].type);
96 mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
101 //fprintf(stderr,"Free block %d to %d (as a new chunck)\n",block,block+mdp->heapinfo[block].busy_block.size);
102 /* Really link this block back into the free list. */
103 mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
104 mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
105 mdp->heapinfo[block].free_block.prev = i;
106 mdp->heapinfo[i].free_block.next = block;
107 mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
108 mdp -> heapstats.chunks_free++;
109 /* Mark all my ex-blocks as free */
110 for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
111 if (mdp->heapinfo[block+it].type <0) {
112 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",
113 (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].free_block.size,(unsigned long)mdp->heapinfo[block].type);
116 mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
120 /* Now that the block is linked in, see if we can coalesce it
121 with its successor (by deleting its successor from the list
122 and adding in its size). */
123 if (block + mdp->heapinfo[block].free_block.size ==
124 mdp->heapinfo[block].free_block.next) {
125 mdp->heapinfo[block].free_block.size
126 += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
127 mdp->heapinfo[block].free_block.next
128 = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
129 mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
130 mdp -> heapstats.chunks_free--;
133 /* Now see if we can return stuff to the system. */
134 /* blocks = mdp -> heapinfo[block].free.size;
135 if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
136 && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
138 register size_t bytes = blocks * BLOCKSIZE;
139 mdp -> heaplimit -= blocks;
140 mdp -> morecore (mdp, -bytes);
141 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
142 = mdp -> heapinfo[block].free.next;
143 mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
144 = mdp -> heapinfo[block].free.prev;
145 block = mdp -> heapinfo[block].free.prev;
146 mdp -> heapstats.chunks_free--;
147 mdp -> heapstats.bytes_free -= bytes;
150 /* Set the next search to begin at this block.
151 This is probably important to the trick where realloc returns the block to
152 the system before reasking for the same block with a bigger size. */
153 mdp->heapindex = block;
158 fprintf(stderr, "Unkown mmalloc block type.\n");
162 /* Do some of the statistics. */
163 mdp -> heapstats.chunks_used--;
164 mdp -> heapstats.bytes_used -= 1 << type;
165 mdp -> heapstats.chunks_free++;
166 mdp -> heapstats.bytes_free += 1 << type;
168 frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
170 if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
172 THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
176 if(mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
177 MC_remove_ignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
180 /* Set size used in the fragment to -1 */
181 mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
182 mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
184 // fprintf(stderr,"nfree:%zu capa:%d\n", mdp->heapinfo[block].busy_frag.nfree,(BLOCKSIZE >> type));
185 if (mdp->heapinfo[block].busy_frag.nfree ==
186 (BLOCKSIZE >> type) - 1) {
187 /* If all fragments of this block are free, remove this block from its swag and free the whole block. */
188 xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
190 /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
191 mdp->heapinfo[block].type = MMALLOC_TYPE_UNFRAGMENTED;
192 mdp->heapinfo[block].busy_block.size = 1;
193 mdp->heapinfo[block].busy_block.busy_size = 0;
195 /* Keep the statistics accurate. */
196 mdp -> heapstats.chunks_used++;
197 mdp -> heapstats.bytes_used += BLOCKSIZE;
198 mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
199 mdp -> heapstats.bytes_free -= BLOCKSIZE;
201 mfree((void *) mdp, (void *) ADDRESS(block));
202 } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
203 /* If some fragments of this block are free, you know what? I'm already happy. */
204 ++mdp->heapinfo[block].busy_frag.nfree;
206 /* No fragments of this block were free before the one we just released,
207 * so add this block to the swag and announce that
208 it is the first free fragment of this block. */
209 mdp->heapinfo[block].busy_frag.nfree = 1;
210 mdp->heapinfo[block].freehook.prev = NULL;
211 mdp->heapinfo[block].freehook.next = NULL;
213 xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);