Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
I meant to paraphrase the expression 'give me liberty or give me death', actually
[simgrid.git] / src / xbt / mmalloc / mfree.c
1 /* Free a block of memory allocated by `mmalloc'.
2    Copyright 1990, 1991, 1992 Free Software Foundation
3
4    Written May 1989 by Mike Haertel.
5    Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com) */
6
7 /* Copyright (c) 2010-2013. The SimGrid Team.
8  * All rights reserved.                                                     */
9
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. */
12
13 #include "mmprivate.h"
14 #include "xbt/ex.h"
15 #include "mc/mc.h"
16
17 /* Return memory to the heap.
18    Like `mfree' but don't call a mfree_hook if there is one.  */
19
20 /* Return memory to the heap.  */
21 void mfree(struct mdesc *mdp, void *ptr)
22 {
23   int type;
24   size_t block, frag_nb;
25   register size_t i;
26   int it;
27
28   mmalloc_paranoia(mdp);
29 //  fprintf(stderr,"free(%p)\n",ptr);
30
31   if (ptr == NULL)
32     return;
33
34   block = BLOCK(ptr);
35
36   if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
37     fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
38     abort();
39   }
40
41   type = mdp->heapinfo[block].type;
42
43   switch (type) {
44   case -1: /* Already free */
45     UNLOCK(mdp);
46     THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled\n");
47     break;
48     
49   case 0:
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;
56
57     if(MC_is_active()){
58       if(mdp->heapinfo[block].busy_block.ignore > 0)
59         MC_remove_ignore_heap(ptr, mdp -> heapinfo[block].busy_block.busy_size);
60     }
61
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.  */
65     i = mdp->heapindex;
66     if (i > block) {
67       while (i > block) {
68         i = mdp->heapinfo[i].free_block.prev;
69       }
70     } else {
71       do {
72         i = mdp->heapinfo[i].free_block.next;
73       }
74       while ((i != 0) && (i < block));
75       i = mdp->heapinfo[i].free_block.prev;
76     }
77
78     /* Determine how to link this block into the free list.  */
79     if (block == i + mdp->heapinfo[i].free_block.size) {
80
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);
88           abort();
89         }
90         mdp->heapinfo[block+it].type = -1;
91       }
92
93       block = i;
94     } else {
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);
108           abort();
109         }
110         mdp->heapinfo[block+it].type = -1;
111       }
112     }
113
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--;
125     }
126
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))
131           {
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;
142           } */
143
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;
148     break;
149
150   default:
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;
156
157     frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
158
159     if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
160       UNLOCK(mdp);
161       THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
162     }
163
164     if(MC_is_active()){
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]);
167     }
168
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;
172
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]);
178
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;
183             
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;
189       
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;
194     } else {
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;
201
202       xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
203     }
204     break;
205   }
206 }
207