Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
5294c14e4972fbc181f3428ec42bb747219b8d2d
[simgrid.git] / src / xbt / mmalloc / mfree.c
1 /* Free a block of memory allocated by `mmalloc'. */
2
3 /* Copyright (c) 2010-2017. The SimGrid Team. All rights reserved.          */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 /* Copyright 1990, 1991, 1992 Free Software Foundation
9
10    Written May 1989 by Mike Haertel.
11    Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com) */
12
13 #include "mmprivate.h"
14 #include "xbt/ex.h"
15 #include "mc/mc.h"
16 #include "src/mc/mc_ignore.h"
17
18 /* Return memory to the heap.
19    Like `mfree' but don't call a mfree_hook if there is one.  */
20
21 /* Return memory to the heap.  */
22 void mfree(struct mdesc *mdp, void *ptr)
23 {
24   int type;
25   size_t block, frag_nb;
26   size_t i;
27   int it;
28
29   mmalloc_paranoia(mdp);
30 //  fprintf(stderr,"free(%p)\n",ptr);
31
32   if (ptr == NULL)
33     return;
34
35   block = BLOCK(ptr);
36
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");
39     abort();
40   }
41
42   type = mdp->heapinfo[block].type;
43
44   switch (type) {
45   case MMALLOC_TYPE_HEAPINFO:
46     UNLOCK(mdp);
47     THROWF(system_error, 0, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
48     break;
49
50   case MMALLOC_TYPE_FREE: /* Already free */
51     UNLOCK(mdp);
52     THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
53     break;
54
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;
62
63     if(MC_is_active()){
64       if(mdp->heapinfo[block].busy_block.ignore > 0)
65         MC_remove_ignore_heap(ptr, mdp -> heapinfo[block].busy_block.busy_size);
66     }
67
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.  */
71     i = mdp->heapindex;
72     if (i > block) {
73       while (i > block) {
74         i = mdp->heapinfo[i].free_block.prev;
75       }
76     } else {
77       do {
78         i = mdp->heapinfo[i].free_block.next;
79       }
80       while ((i != 0) && (i < block));
81       i = mdp->heapinfo[i].free_block.prev;
82     }
83
84     /* Determine how to link this block into the free list.  */
85     if (block == i + mdp->heapinfo[i].free_block.size) {
86
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);
94           abort();
95         }
96         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
97       }
98
99       block = i;
100     } else {
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);
114           abort();
115         }
116         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
117       }
118     }
119
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--;
131     }
132
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))
137           {
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;
148           } */
149
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;
154     break;
155
156   default:
157     if (type < 0) {
158       fprintf(stderr, "Unkown mmalloc block type.\n");
159       abort();
160     }
161
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;
167
168     frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
169
170     if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
171       UNLOCK(mdp);
172       THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
173     }
174
175     if(MC_is_active()){
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]);
178     }
179
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;
183
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]);
189
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;
194
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;
200
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;
205     } else {
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;
212
213       xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
214     }
215     break;
216   }
217 }