Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'actor-yield' of github.com:Takishipp/simgrid into actor-yield
[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
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   size_t frag_nb;
24   size_t i;
25   int it;
26
27 //  fprintf(stderr,"free(%p)\n",ptr);
28
29   if (ptr == NULL)
30     return;
31
32   size_t block = BLOCK(ptr);
33
34   if ((char *) ptr < (char *) mdp->heapbase || block > mdp->heapsize) {
35     fprintf(stderr,"Ouch, this pointer is not mine, I refuse to free it. Give me valid pointers, or give me death!!\n");
36     abort();
37   }
38
39   int type = mdp->heapinfo[block].type;
40
41   switch (type) {
42   case MMALLOC_TYPE_HEAPINFO:
43     UNLOCK(mdp);
44     THROWF(system_error, 0, "Asked to free a fragment in a heapinfo block. I'm confused.\n");
45     break;
46
47   case MMALLOC_TYPE_FREE: /* Already free */
48     UNLOCK(mdp);
49     THROWF(system_error, 0, "Asked to free a fragment in a block that is already free. I'm puzzled.\n");
50     break;
51
52   case MMALLOC_TYPE_UNFRAGMENTED:
53     /* Get as many statistics as early as we can.  */
54     mdp -> heapstats.chunks_used--;
55     mdp -> heapstats.bytes_used -=
56       mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
57     mdp -> heapstats.bytes_free +=
58       mdp -> heapinfo[block].busy_block.size * BLOCKSIZE;
59
60     if (MC_is_active() && mdp->heapinfo[block].busy_block.ignore > 0)
61       MC_unignore_heap(ptr, mdp->heapinfo[block].busy_block.busy_size);
62
63     /* Find the free cluster previous to this one in the free list.
64        Start searching at the last block referenced; this may benefit
65        programs with locality of allocation.  */
66     i = mdp->heapindex;
67     if (i > block) {
68       while (i > block) {
69         i = mdp->heapinfo[i].free_block.prev;
70       }
71     } else {
72       do {
73         i = mdp->heapinfo[i].free_block.next;
74       }
75       while ((i != 0) && (i < block));
76       i = mdp->heapinfo[i].free_block.prev;
77     }
78
79     /* Determine how to link this block into the free list.  */
80     if (block == i + mdp->heapinfo[i].free_block.size) {
81
82       /* Coalesce this block with its predecessor.  */
83       mdp->heapinfo[i].free_block.size += mdp->heapinfo[block].busy_block.size;
84       /* Mark all my ex-blocks as free */
85       for (it=0; it<mdp->heapinfo[block].busy_block.size; it++) {
86         if (mdp->heapinfo[block+it].type < 0) {
87           fprintf(stderr,"Internal Error: Asked to free a block already marked as free (block=%lu it=%d type=%lu). Please report this bug.\n",
88                   (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].type);
89           abort();
90         }
91         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
92       }
93
94       block = i;
95     } else {
96       //fprintf(stderr,"Free block %d to %d (as a new chunck)\n",block,block+mdp->heapinfo[block].busy_block.size);
97       /* Really link this block back into the free list.  */
98       mdp->heapinfo[block].free_block.size = mdp->heapinfo[block].busy_block.size;
99       mdp->heapinfo[block].free_block.next = mdp->heapinfo[i].free_block.next;
100       mdp->heapinfo[block].free_block.prev = i;
101       mdp->heapinfo[i].free_block.next = block;
102       mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
103       mdp -> heapstats.chunks_free++;
104       /* Mark all my ex-blocks as free */
105       for (it=0; it<mdp->heapinfo[block].free_block.size; it++) {
106         if (mdp->heapinfo[block+it].type <0) {
107           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",
108                   (unsigned long)block,it,(unsigned long)mdp->heapinfo[block].free_block.size,(unsigned long)mdp->heapinfo[block].type);
109           abort();
110         }
111         mdp->heapinfo[block+it].type = MMALLOC_TYPE_FREE;
112       }
113     }
114
115     /* Now that the block is linked in, see if we can coalesce it
116        with its successor (by deleting its successor from the list
117        and adding in its size).  */
118     if (block + mdp->heapinfo[block].free_block.size ==
119         mdp->heapinfo[block].free_block.next) {
120       mdp->heapinfo[block].free_block.size
121         += mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.size;
122       mdp->heapinfo[block].free_block.next
123         = mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.next;
124       mdp->heapinfo[mdp->heapinfo[block].free_block.next].free_block.prev = block;
125       mdp -> heapstats.chunks_free--;
126     }
127
128     /* Now see if we can return stuff to the system.  */
129     /*    blocks = mdp -> heapinfo[block].free.size;
130           if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
131           && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
132           {
133           register size_t bytes = blocks * BLOCKSIZE;
134           mdp -> heaplimit -= blocks;
135           mdp -> morecore (mdp, -bytes);
136           mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
137           = mdp -> heapinfo[block].free.next;
138           mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
139           = mdp -> heapinfo[block].free.prev;
140           block = mdp -> heapinfo[block].free.prev;
141           mdp -> heapstats.chunks_free--;
142           mdp -> heapstats.bytes_free -= bytes;
143           } */
144
145     /* Set the next search to begin at this block.
146        This is probably important to the trick where realloc returns the block to
147        the system before reasking for the same block with a bigger size.  */
148     mdp->heapindex = block;
149     break;
150
151   default:
152     if (type < 0) {
153       fprintf(stderr, "Unkown mmalloc block type.\n");
154       abort();
155     }
156
157     /* Do some of the statistics.  */
158     mdp -> heapstats.chunks_used--;
159     mdp -> heapstats.bytes_used -= 1 << type;
160     mdp -> heapstats.chunks_free++;
161     mdp -> heapstats.bytes_free += 1 << type;
162
163     frag_nb = RESIDUAL(ptr, BLOCKSIZE) >> type;
164
165     if( mdp->heapinfo[block].busy_frag.frag_size[frag_nb] == -1){
166       UNLOCK(mdp);
167       THROWF(system_error, 0, "Asked to free a fragment that is already free. I'm puzzled\n");
168     }
169
170     if (MC_is_active() && mdp->heapinfo[block].busy_frag.ignore[frag_nb] > 0)
171       MC_unignore_heap(ptr, mdp->heapinfo[block].busy_frag.frag_size[frag_nb]);
172
173     /* Set size used in the fragment to -1 */
174     mdp->heapinfo[block].busy_frag.frag_size[frag_nb] = -1;
175     mdp->heapinfo[block].busy_frag.ignore[frag_nb] = 0;
176
177 //    fprintf(stderr,"nfree:%zu capa:%d\n", mdp->heapinfo[block].busy_frag.nfree,(BLOCKSIZE >> type));
178     if (mdp->heapinfo[block].busy_frag.nfree ==
179         (BLOCKSIZE >> type) - 1) {
180       /* If all fragments of this block are free, remove this block from its swag and free the whole block.  */
181       xbt_swag_remove(&mdp->heapinfo[block],&mdp->fraghead[type]);
182
183       /* pretend that this block is used and free it so that it gets properly coalesced with adjacent free blocks */
184       mdp->heapinfo[block].type = MMALLOC_TYPE_UNFRAGMENTED;
185       mdp->heapinfo[block].busy_block.size = 1;
186       mdp->heapinfo[block].busy_block.busy_size = 0;
187
188       /* Keep the statistics accurate.  */
189       mdp -> heapstats.chunks_used++;
190       mdp -> heapstats.bytes_used += BLOCKSIZE;
191       mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
192       mdp -> heapstats.bytes_free -= BLOCKSIZE;
193
194       mfree((void *) mdp, (void *) ADDRESS(block));
195     } else if (mdp->heapinfo[block].busy_frag.nfree != 0) {
196       /* If some fragments of this block are free, you know what? I'm already happy. */
197       ++mdp->heapinfo[block].busy_frag.nfree;
198     } else {
199       /* No fragments of this block were free before the one we just released,
200        * so add this block to the swag and announce that
201        it is the first free fragment of this block. */
202       mdp->heapinfo[block].busy_frag.nfree = 1;
203       mdp->heapinfo[block].freehook.prev = NULL;
204       mdp->heapinfo[block].freehook.next = NULL;
205
206       xbt_swag_insert(&mdp->heapinfo[block],&mdp->fraghead[type]);
207     }
208     break;
209   }
210 }