make dump_alloc work for oversized blocks
[cacao.git] / src / mm / memory.c
1 /* toolbox/memory.c - 
2
3    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
4    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
5    M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
6    P. Tomsich, J. Wenninger
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23    02111-1307, USA.
24
25    Contact: cacao@complang.tuwien.ac.at
26
27    Authors: Reinhard Grafl
28
29    $Id: memory.c 799 2003-12-16 22:30:41Z edwin $
30
31 */
32
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <string.h>
38 #include <sys/mman.h>
39 #include <unistd.h>
40
41 #include "global.h"
42 #include "loging.h"
43 #include "memory.h"
44
45
46 /********* general types, variables and auxiliary functions *********/
47
48 #define DUMPBLOCKSIZE  (2<<21)
49 #define ALIGNSIZE           8
50
51 typedef struct dumplist {
52         struct dumplist *prev;
53         char *dumpmem;
54         int size;
55 } dumplist;
56
57
58
59 long int memoryusage = 0;
60
61 long int dumpsize = 0;
62 long int dumpspace = 0;
63 dumplist *topdumpblock = NULL;
64
65 long int maxmemusage = 0;
66 long int maxdumpsize = 0;
67
68 #define TRACECALLARGS
69
70 #ifdef TRACECALLARGS
71 static char *nomallocmem = NULL;
72 static char *nomalloctop;
73 static char *nomallocptr;
74
75
76 static void *lit_checked_alloc (int length)
77 {
78         void *m;
79
80         if (!nomallocmem) {
81                 nomallocmem = malloc(16777216); 
82                 nomalloctop = nomallocmem + 16777216;
83                 nomallocptr = nomallocmem;
84         }
85
86         nomallocptr = (void*) ALIGN((long) nomallocptr, ALIGNSIZE);
87         
88         m = nomallocptr;
89         nomallocptr += length;
90         if (nomallocptr > nomalloctop)
91                 panic("Out of memory");
92
93         return m;
94 }
95
96 #else
97
98 static void *lit_checked_alloc(int length)
99 {
100         void *m = malloc(length);
101         if (!m) panic ("Out of memory");
102         return m;
103 }
104
105 #endif
106
107
108 static void *checked_alloc(int length)
109 {
110         void *m = malloc(length);
111         if (!m) panic("Out of memory");
112         return m;
113 }
114
115
116 static int mmapcodesize = 0;
117 static void *mmapcodeptr = NULL;
118
119
120 void *mem_mmap(int length)
121 {
122         void *retptr;
123
124         length = (ALIGN(length,ALIGNSIZE));
125         if (length > mmapcodesize) {
126                 mmapcodesize = 0x10000;
127                 if (length > mmapcodesize)
128                         mmapcodesize = length;
129                 mmapcodesize = (ALIGN(mmapcodesize, getpagesize()));
130                 mmapcodeptr = mmap (NULL, (size_t) mmapcodesize,
131                                                         PROT_READ | PROT_WRITE | PROT_EXEC,
132                                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0);
133                 if (mmapcodeptr == (void*) -1)
134                         panic ("Out of memory");
135         }
136         retptr = mmapcodeptr;
137         mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
138         mmapcodesize -= length;
139         return retptr;
140 }
141
142
143 #ifdef DEBUG
144
145 /************ Memory manager, safe version **************/
146
147
148 typedef struct memblock {
149         struct memblock *prev, *next;
150         int length;
151 } memblock;
152
153 #define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
154
155 struct memblock *firstmemblock;
156
157
158
159 void *mem_alloc(int length)
160 {
161         memblock *mb;
162
163         if (length == 0) return NULL;
164         mb = checked_alloc(length + BLOCKOFFSET);
165
166         mb->prev = NULL;
167         mb->next = firstmemblock;       
168         mb->length = length;
169
170         if (firstmemblock) firstmemblock->prev = mb;
171         firstmemblock = mb;
172
173         memoryusage += length;
174         if (memoryusage > maxmemusage)
175                 maxmemusage = memoryusage;
176
177         return ((char*) mb) + BLOCKOFFSET;
178 }
179
180
181 void *lit_mem_alloc(int length)
182 {
183         memblock *mb;
184
185         if (length == 0) return NULL;
186         mb = lit_checked_alloc(length + BLOCKOFFSET);
187
188         mb->prev = NULL;
189         mb->next = firstmemblock;       
190         mb->length = length;
191
192         if (firstmemblock) firstmemblock -> prev = mb;
193         firstmemblock = mb;
194
195         memoryusage += length;
196         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
197
198         return ((char*) mb) + BLOCKOFFSET;
199 }
200
201
202 void mem_free(void *m, int length)
203 {
204         memblock *mb;
205         if (!m) {
206                 if (length == 0) return;
207                 panic("returned memoryblock with address NULL, length != 0");
208         }
209
210         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
211         
212         if (mb->length != length) {
213                 sprintf(logtext, 
214                                 "Memory block of size %d has been return as size %d",
215                                 mb->length, length);
216                 error();
217         }
218                 
219         if (mb->prev) mb->prev->next = mb->next;
220         else firstmemblock = mb->next;
221         if (mb->next) mb->next->prev = mb->prev;
222
223         free (mb);
224
225         memoryusage -= length;
226 }
227
228
229 void lit_mem_free(void *m, int length)
230 {
231         memblock *mb;
232         if (!m) {
233                 if (length==0) return;
234                 panic("returned memoryblock with address NULL, length != 0");
235         }
236
237         mb = (memblock*) (((char*) m) - BLOCKOFFSET);
238         
239         if (mb->length != length) {
240                 sprintf(logtext, 
241                                 "Memory block of size %d has been return as size %d",
242                                 mb->length, length);
243                 error();
244         }
245                 
246         if (mb->prev) mb->prev->next = mb->next;
247         else firstmemblock = mb->next;
248         if (mb->next) mb->next->prev = mb->prev;
249
250 #ifdef TRACECALLARGS
251 #else
252         free(mb);
253 #endif
254
255         memoryusage -= length;
256 }
257
258
259 void *mem_realloc(void *m1, int len1, int len2)
260 {
261         void *m2;
262         
263         m2 = mem_alloc(len2);
264         memcpy(m2, m1, len1);
265         mem_free(m1, len1);
266
267         return m2;
268 }
269
270
271
272
273 static void mem_characterlog(unsigned char *m, int len)
274 {
275 #       define LINESIZE 16
276         int z, i;
277         char logtext[MAXLOGTEXT];
278         
279         for (z = 0; z < len; z += LINESIZE) {
280                 sprintf(logtext, "   ");
281                         
282                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
283                         sprintf(logtext + strlen(logtext), "%2x ", m[i]);
284                 }
285                 for (; i < (z + LINESIZE); i++) {
286                         sprintf(logtext + strlen(logtext), "   ");
287                 }
288                                         
289                 sprintf(logtext + strlen(logtext),"   ");
290                 for (i = z; i < (z + LINESIZE) && i < len; i++) {
291                         sprintf(logtext+strlen(logtext),
292                                         "%c", (m[i] >= ' ' && m[i] <= 127) ? m[i] : '.');
293                 }
294                         
295                 log_text(logtext);
296         }
297 }
298
299 #else
300 /******* Memory manager, fast version ******/
301
302
303 void *mem_alloc(int length)
304 {
305         if (length == 0) return NULL;
306
307         memoryusage += length;
308         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
309         
310         return checked_alloc(length);
311 }
312
313
314 void *lit_mem_alloc(int length)
315 {
316         if (length == 0) return NULL;
317
318         memoryusage += length;
319         if (memoryusage > maxmemusage) maxmemusage = memoryusage;
320         
321         return lit_checked_alloc(length);
322 }
323
324
325 void mem_free(void *m, int length)
326 {
327         if (!m) {
328                 if (length == 0) return;
329                 panic("returned memoryblock with address NULL, length != 0");
330         }
331
332         memoryusage -= length;
333
334         free(m);
335 }
336
337
338 void lit_mem_free(void *m, int length)
339 {
340         if (!m) {
341                 if (length == 0) return;
342                 panic("returned memoryblock with address NULL, length != 0");
343         }
344
345         memoryusage -= length;
346
347 #ifdef TRACECALLARGS
348 #else
349         free(m);
350 #endif
351 }
352
353
354 void *mem_realloc (void *m1, int len1, int len2)
355 {
356         void *m2;
357
358         if (!m1) {
359                 if (len1!=0) 
360                         panic ("reallocating memoryblock with address NULL, length != 0");
361         }
362                 
363         memoryusage = (memoryusage - len1) + len2;
364
365         m2 = realloc (m1, len2);
366         if (!m2) panic ("Out of memory");
367         return m2;
368 }
369
370
371 #endif
372
373 /******* common memory manager parts ******/
374
375 long int mem_usage()
376 {
377         return memoryusage;
378 }
379
380
381 void *dump_alloc(int length)
382 {
383         void *m;
384         int blocksize = DUMPBLOCKSIZE;
385
386         if (length == 0) return NULL;
387         
388         length = ALIGN(length, ALIGNSIZE);
389
390         if (length > DUMPBLOCKSIZE)
391                 blocksize = length;
392         assert(length > 0);
393
394         if (dumpsize + length > dumpspace) {
395                 dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
396
397                 newdumpblock->prev = topdumpblock;
398                 newdumpblock->size = blocksize;
399                 topdumpblock = newdumpblock;
400
401                 newdumpblock->dumpmem = checked_alloc(blocksize);
402
403                 dumpsize = dumpspace;
404                 dumpspace += blocksize;
405         }
406         
407         m = topdumpblock->dumpmem + blocksize - (dumpspace - dumpsize);
408         dumpsize += length;
409         
410         if (dumpsize > maxdumpsize) {
411                 maxdumpsize = dumpsize;
412         }
413                 
414         return m;
415 }   
416
417
418 void *dump_realloc(void *ptr, int len1, int len2)
419 {
420         void *p2 = dump_alloc(len2);
421         memcpy(p2, ptr, len1);  
422         return p2;
423 }
424
425
426 long int dump_size()
427 {
428         return dumpsize;
429 }
430
431
432 void dump_release(long int size)
433 {
434         assert(size >= 0 && size <= dumpsize);
435
436         dumpsize = size;
437         
438         while (topdumpblock && (dumpspace - topdumpblock->size >= dumpsize)) {
439                 dumplist *oldtop = topdumpblock;
440
441 #ifdef TRACECALLARGS
442                 /* Keep the first dumpblock if we don't free memory. Otherwise
443                  * a new dumpblock is allocated each time and we run out of
444                  * memory.
445                  */
446                 if (!oldtop->prev) break;
447 #endif
448                 
449                 dumpspace -= oldtop->size;
450                 topdumpblock = oldtop->prev;
451                 
452 #ifdef TRACECALLARGS
453 #else
454                 free(oldtop->dumpmem);
455                 free(oldtop);
456 #endif
457         }               
458 }
459
460
461 void mem_usagelog (int givewarnings)
462 {
463         if ((memoryusage!=0) && givewarnings) {
464                 dolog ("Allocated memory not returned: %d",
465                                  (int)memoryusage);
466
467 #ifdef DEBUG
468                 { 
469                         memblock *mb = firstmemblock;
470                         while (mb) {
471                                 dolog ("   Memory block size: %d", 
472                                                  (int)(mb->length) );
473                                 mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
474                                 mb = mb->next;
475                         }
476                 }
477 #endif
478                         
479         }
480
481         if ((dumpsize!=0) && givewarnings) {
482                 dolog ("Dump memory not returned: %d",(int)dumpsize);
483         }
484
485
486         dolog("Random/Dump - memory usage: %dK/%dK", 
487                         (int)((maxmemusage+1023)/1024), 
488                         (int)((maxdumpsize+1023)/1024) );
489         
490 }
491
492
493 /*
494  * These are local overrides for various environment variables in Emacs.
495  * Please do not remove this and leave it at the end of the file, where
496  * Emacs will automagically detect them.
497  * ---------------------------------------------------------------------
498  * Local variables:
499  * mode: c
500  * indent-tabs-mode: t
501  * c-basic-offset: 4
502  * tab-width: 4
503  * End:
504  */