merge with/from trunk at r35190
[blender.git] / intern / guardedalloc / intern / mallocn.c
1 /*
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file guardedalloc/intern/mallocn.c
30  *  \ingroup MEM
31  */
32
33
34 /**
35
36  * $Id$
37  * Copyright (C) 2001 NaN Technologies B.V.
38  * Guarded memory allocation, and boundary-write detection.
39  */
40
41 #include <stdlib.h>
42 #include <string.h>     /* memcpy */
43 #include <stdarg.h>
44 #include <sys/types.h>
45 /* Blame Microsoft for LLP64 and no inttypes.h, quick workaround needed: */
46 #if defined(WIN64)
47 #define SIZET_FORMAT "%I64u"
48 #define SIZET_ARG(a) ((unsigned long long)(a))
49 #else
50 #define SIZET_FORMAT "%lu"
51 #define SIZET_ARG(a) ((unsigned long)(a))
52 #endif
53
54 /* mmap exception */
55 #if defined(WIN32)
56 #include "mmap_win.h"
57 #else
58 #include <sys/mman.h>
59 #endif
60
61 #include "MEM_guardedalloc.h"
62
63 /* Only for debugging:
64  * lets you count the allocations so as to find the allocator of unfreed memory
65  * in situations where the leak is predictable */
66
67 // #define DEBUG_MEMCOUNTER
68
69 #ifdef DEBUG_MEMCOUNTER
70 #define DEBUG_MEMCOUNTER_ERROR_VAL 0 /* set this to the value that isnt being freed */
71 static int _mallocn_count = 0;
72
73 /* breakpoint here */
74 static void memcount_raise(const char *name)
75 {
76         fprintf(stderr, "%s: memcount-leak, %d\n", name, _mallocn_count);
77 }
78 #endif
79
80 /* --------------------------------------------------------------------- */
81 /* Data definition                                                       */
82 /* --------------------------------------------------------------------- */
83
84 /* --------------------------------------------------------------------- */
85 /* local functions                                                       */
86 /* --------------------------------------------------------------------- */
87
88 static void addtail(volatile localListBase *listbase, void *vlink);
89 static void remlink(volatile localListBase *listbase, void *vlink);
90 static void rem_memblock(MemHead *memh);
91 static void MemorY_ErroR(const char *block, const char *error);
92 static const char *check_memlist(MemHead *memh);
93
94 /* --------------------------------------------------------------------- */
95 /* locally used defines                                                  */
96 /* --------------------------------------------------------------------- */
97
98 #if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__))
99 #define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
100 #else
101 #define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
102 #endif
103
104 #define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
105 #define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
106 #define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
107 #define MEMTAG4 MAKE_ID('C', 'R', 'A', 'P')
108 #define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
109
110 #define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next))))
111         
112 /* --------------------------------------------------------------------- */
113 /* vars                                                                  */
114 /* --------------------------------------------------------------------- */
115         
116
117 static volatile int totblock= 0;
118 static volatile uintptr_t mem_in_use= 0, mmap_in_use= 0, peak_mem = 0;
119
120 static volatile struct localListBase _membase;
121 static volatile struct localListBase *membase = &_membase;
122 static void (*error_callback)(const char *) = NULL;
123 static void (*thread_lock_callback)(void) = NULL;
124 static void (*thread_unlock_callback)(void) = NULL;
125
126 static int malloc_debug_memset= 0;
127
128 #ifdef malloc
129 #undef malloc
130 #endif
131
132 #ifdef calloc
133 #undef calloc
134 #endif
135
136 #ifdef free
137 #undef free
138 #endif
139
140
141 /* --------------------------------------------------------------------- */
142 /* implementation                                                        */
143 /* --------------------------------------------------------------------- */
144
145 static void print_error(const char *str, ...)
146 {
147         char buf[512];
148         va_list ap;
149
150         va_start(ap, str);
151         vsnprintf(buf, sizeof(buf), str, ap);
152         va_end(ap);
153         buf[sizeof(buf) - 1] = '\0';
154
155         if (error_callback) error_callback(buf);
156 }
157
158 static void mem_lock_thread(void)
159 {
160         if (thread_lock_callback)
161                 thread_lock_callback();
162 }
163
164 static void mem_unlock_thread(void)
165 {
166         if (thread_unlock_callback)
167                 thread_unlock_callback();
168 }
169
170 int MEM_check_memory_integrity()
171 {
172         const char* err_val = NULL;
173         MemHead* listend;
174         /* check_memlist starts from the front, and runs until it finds
175          * the requested chunk. For this test, that's the last one. */
176         listend = membase->last;
177         
178         err_val = check_memlist(listend);
179
180         if (err_val == 0) return 0;
181         return 1;
182 }
183
184
185 void MEM_set_error_callback(void (*func)(const char *))
186 {
187         error_callback = func;
188 }
189
190 void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void))
191 {
192         thread_lock_callback = lock;
193         thread_unlock_callback = unlock;
194 }
195
196 void MEM_set_memory_debug(void)
197 {
198         malloc_debug_memset= 1;
199 }
200
201 size_t MEM_allocN_len(void *vmemh)
202 {
203         if (vmemh) {
204                 MemHead *memh= vmemh;
205         
206                 memh--;
207                 return memh->len;
208         } else
209                 return 0;
210 }
211
212 void *MEM_reallocN(void *vmemh, size_t len)
213 {
214         void *newp= NULL;
215         
216         if (vmemh) {
217                 MemHead *memh= vmemh;
218                 memh--;
219                 
220                 if(memh->mmap)
221                         newp= MEM_mapallocN(len, "dupli_mapalloc");
222                 else
223                         newp= MEM_mallocN(len, "dupli_alloc");
224
225                 if (newp == NULL) return NULL;
226
227                 memcpy(newp, vmemh, len<=memh->len ? len : memh->len);
228         }
229
230         return newp;
231 }
232
233
234 void *MEM_dupallocN(void *vmemh)
235 {
236         void *newp= NULL;
237
238         if (vmemh) {
239                 MemHead *memh= vmemh;
240                 memh--;
241
242                 if(memh->mmap)
243                         newp= MEM_mapallocN(memh->len, "dupli_mapalloc");
244                 else
245                         newp= MEM_mallocN(memh->len, "dupli_alloc");
246
247                 if (newp == NULL) return NULL;
248
249                 memcpy(newp, vmemh, memh->len);
250         }
251
252         return newp;
253 }
254
255 static void make_memhead_header(MemHead *memh, size_t len, const char *str)
256 {
257         MemTail *memt;
258         
259         memh->tag1 = MEMTAG1;
260         memh->name = str;
261         memh->nextname = 0;
262         memh->len = len;
263         memh->mmap = 0;
264         memh->tag2 = MEMTAG2;
265         
266         memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
267         memt->tag3 = MEMTAG3;
268         memt->tag4 = MEMTAG4;
269         
270         addtail(membase,&memh->next);
271         if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
272         
273         totblock++;
274         mem_in_use += len;
275
276         peak_mem = mem_in_use > peak_mem ? mem_in_use : peak_mem;
277 }
278
279 void *MEM_mallocN(size_t len, const char *str)
280 {
281         MemHead *memh;
282
283         mem_lock_thread();
284
285         len = (len + 3 ) & ~3;  /* allocate in units of 4 */
286         
287         memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail));
288
289         if(memh) {
290                 make_memhead_header(memh, len, str);
291                 mem_unlock_thread();
292                 if(malloc_debug_memset && len)
293                         memset(memh+1, 255, len);
294                 return (++memh);
295         }
296         mem_unlock_thread();
297         print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use);
298         return NULL;
299 }
300
301 void *MEM_callocN(size_t len, const char *str)
302 {
303         MemHead *memh;
304
305         mem_lock_thread();
306
307         len = (len + 3 ) & ~3;  /* allocate in units of 4 */
308
309         memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1);
310
311         if(memh) {
312                 make_memhead_header(memh, len, str);
313                 mem_unlock_thread();
314                 return (++memh);
315         }
316         mem_unlock_thread();
317         print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use);
318         return 0;
319 }
320
321 /* note; mmap returns zero'd memory */
322 void *MEM_mapallocN(size_t len, const char *str)
323 {
324         MemHead *memh;
325
326         mem_lock_thread();
327         
328         len = (len + 3 ) & ~3;  /* allocate in units of 4 */
329         
330 #ifdef __sgi
331         {
332 #include <fcntl.h>
333
334           int fd;
335           fd = open("/dev/zero", O_RDWR);
336
337           memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail),
338                      PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
339           close(fd);
340         }
341 #else
342         memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail),
343                    PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
344 #endif
345
346         if(memh!=(MemHead *)-1) {
347                 make_memhead_header(memh, len, str);
348                 memh->mmap= 1;
349                 mmap_in_use += len;
350                 peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem;
351                 mem_unlock_thread();
352                 return (++memh);
353         }
354         else {
355                 mem_unlock_thread();
356                 print_error("Mapalloc returns null, fallback to regular malloc: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mmap_in_use);
357                 return MEM_callocN(len, str);
358         }
359 }
360
361 /* Memory statistics print */
362 typedef struct MemPrintBlock {
363         const char *name;
364         uintptr_t len;
365         int items;
366 } MemPrintBlock;
367
368 static int compare_name(const void *p1, const void *p2)
369 {
370         const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
371         const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
372
373         return strcmp(pb1->name, pb2->name);
374 }
375
376 static int compare_len(const void *p1, const void *p2)
377 {
378         const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
379         const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
380
381         if(pb1->len < pb2->len)
382                 return 1;
383         else if(pb1->len == pb2->len)
384                 return 0;
385         else
386                 return -1;
387 }
388
389 void MEM_printmemlist_stats()
390 {
391         MemHead *membl;
392         MemPrintBlock *pb, *printblock;
393         int totpb, a, b;
394
395         mem_lock_thread();
396
397         /* put memory blocks into array */
398         printblock= malloc(sizeof(MemPrintBlock)*totblock);
399
400         pb= printblock;
401         totpb= 0;
402
403         membl = membase->first;
404         if (membl) membl = MEMNEXT(membl);
405
406         while(membl) {
407                 pb->name= membl->name;
408                 pb->len= membl->len;
409                 pb->items= 1;
410
411                 totpb++;
412                 pb++;
413
414                 if(membl->next)
415                         membl= MEMNEXT(membl->next);
416                 else break;
417         }
418
419         /* sort by name and add together blocks with the same name */
420         qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
421         for(a=0, b=0; a<totpb; a++) {
422                 if(a == b) {
423                         continue;
424                 }
425                 else if(strcmp(printblock[a].name, printblock[b].name) == 0) {
426                         printblock[b].len += printblock[a].len;
427                         printblock[b].items++;
428                 }
429                 else {
430                         b++;
431                         memcpy(&printblock[b], &printblock[a], sizeof(MemPrintBlock));
432                 }
433         }
434         totpb= b+1;
435
436         /* sort by length and print */
437         qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
438         printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use/(double)(1024*1024));
439         printf(" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
440         for(a=0, pb=printblock; a<totpb; a++, pb++)
441                 printf("%6d (%8.3f  %8.3f) %s\n", pb->items, (double)pb->len/(double)(1024*1024), (double)pb->len/1024.0/(double)pb->items, pb->name);
442
443         free(printblock);
444         
445         mem_unlock_thread();
446
447 #if 0 /* GLIBC only */
448         malloc_stats();
449 #endif
450 }
451
452 /* Prints in python syntax for easy */
453 static void MEM_printmemlist_internal( int pydict )
454 {
455         MemHead *membl;
456
457         mem_lock_thread();
458
459         membl = membase->first;
460         if (membl) membl = MEMNEXT(membl);
461         
462         if (pydict) {
463                 print_error("# membase_debug.py\n");
464                 print_error("membase = [\\\n");
465         }
466         while(membl) {
467                 if (pydict) {
468                         fprintf(stderr, "{'len':" SIZET_FORMAT ", 'name':'''%s''', 'pointer':'%p'},\\\n", SIZET_ARG(membl->len), membl->name, (void *)(membl+1));
469                 } else {
470 #ifdef DEBUG_MEMCOUNTER
471                         print_error("%s len: " SIZET_FORMAT " %p, count: %d\n", membl->name, SIZET_ARG(membl->len), membl+1, membl->_count);
472 #else
473                         print_error("%s len: " SIZET_FORMAT " %p\n", membl->name, SIZET_ARG(membl->len), membl+1);
474 #endif
475                 }
476                 if(membl->next)
477                         membl= MEMNEXT(membl->next);
478                 else break;
479         }
480         if (pydict) {
481                 fprintf(stderr, "]\n\n");
482                 fprintf(stderr,
483 "mb_userinfo = {}\n"
484 "totmem = 0\n"
485 "for mb_item in membase:\n"
486 "\tmb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
487 "\tmb_item_user_size[0] += 1 # Add a user\n"
488 "\tmb_item_user_size[1] += mb_item['len'] # Increment the size\n"
489 "\ttotmem += mb_item['len']\n"
490 "print '(membase) items:', len(membase), '| unique-names:', len(mb_userinfo), '| total-mem:', totmem\n"
491 "mb_userinfo_sort = mb_userinfo.items()\n"
492 "for sort_name, sort_func in (('size', lambda a: -a[1][1]), ('users', lambda a: -a[1][0]), ('name', lambda a: a[0])):\n"
493 "\tprint '\\nSorting by:', sort_name\n"
494 "\tmb_userinfo_sort.sort(key = sort_func)\n"
495 "\tfor item in mb_userinfo_sort:\n"
496 "\t\tprint 'name:%%s, users:%%i, len:%%i' %% (item[0], item[1][0], item[1][1])\n"
497                 );
498         }
499         
500         mem_unlock_thread();
501 }
502
503 void MEM_callbackmemlist(void (*func)(void*)) {
504         MemHead *membl;
505
506         mem_lock_thread();
507
508         membl = membase->first;
509         if (membl) membl = MEMNEXT(membl);
510
511         while(membl) {
512                 func(membl+1);
513                 if(membl->next)
514                         membl= MEMNEXT(membl->next);
515                 else break;
516         }
517
518         mem_unlock_thread();
519 }
520
521 short MEM_testN(void *vmemh) {
522         MemHead *membl;
523
524         mem_lock_thread();
525
526         membl = membase->first;
527         if (membl) membl = MEMNEXT(membl);
528
529         while(membl) {
530                 if (vmemh == membl+1)
531                         return 1;
532
533                 if(membl->next)
534                         membl= MEMNEXT(membl->next);
535                 else break;
536         }
537
538         mem_unlock_thread();
539
540         print_error("Memoryblock %p: pointer not in memlist\n", vmemh);
541         return 0;
542 }
543
544 void MEM_printmemlist( void ) {
545         MEM_printmemlist_internal(0);
546 }
547 void MEM_printmemlist_pydict( void ) {
548         MEM_printmemlist_internal(1);
549 }
550
551 #ifdef MEM_freeN
552 #undef MEM_freeN
553 #endif
554
555 short MEM_freeN(void *vmemh)
556 {
557         return _MEM_freeN(vmemh, "(called through C stub function)", -1);
558 }
559
560 short WMEM_freeN(void *vmemh)
561 {
562         return _MEM_freeN(vmemh, "(called through C stub function)", -1);
563 }
564
565 /*special macro-wrapped MEM_freeN that keeps track of where MEM_freeN is called.*/
566 short _MEM_freeN(void *vmemh, const char *file, int line)               /* anders compileertie niet meer */
567 {
568         short error = 0;
569         MemTail *memt;
570         MemHead *memh= vmemh;
571         const char *name;
572         char str1[90];
573         
574         if (memh == NULL){
575                 sprintf(str1, "Error in %s on line %d: attempt to free NULL pointer", file, line);
576                 MemorY_ErroR("free", str1);
577                 /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
578                 return(-1);
579         }
580
581         if(sizeof(intptr_t)==8) {
582                 if (((intptr_t) memh) & 0x7) {
583                         sprintf(str1, "Error in %s on line %d: attempt to free illegal pointer", file, line);
584                         MemorY_ErroR("free", str1);
585                         return(-1);
586                 }
587         }
588         else {
589                 if (((intptr_t) memh) & 0x3) {
590                         sprintf(str1, "Error in %s on line %d: attempt to free illegal pointer", file, line);
591                         MemorY_ErroR("free", str1);
592                         return(-1);
593                 }
594         }
595         
596         memh--;
597         if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
598                 sprintf(str1, "Error in %s on line %d: double free", file, line);
599                 MemorY_ErroR(memh->name, str1);
600                 return(-1);
601         }
602
603         mem_lock_thread();
604         if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
605                 memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len);
606                 if (memt->tag3 == MEMTAG3 && memt->tag4 == MEMTAG4){
607                         
608                         memh->tag1 = MEMFREE;
609                         memh->tag2 = MEMFREE;
610                         memt->tag3 = MEMFREE;
611                         memt->tag4 = MEMFREE;
612                         /* after tags !!! */
613                         rem_memblock(memh);
614
615                         mem_unlock_thread();
616                         
617                         return(0);
618                 }
619                 error = 2;
620                 MemorY_ErroR(memh->name,"end corrupt");
621                 name = check_memlist(memh);
622                 if (name != 0){
623                         sprintf(str1, "Error in %s on line %d: %s is also corrupt", file, line, name);
624                         if (name != memh->name) MemorY_ErroR(name, str1);
625                 }
626         } else{
627                 error = -1;
628                 name = check_memlist(memh);
629                 if (name == 0) {
630                         sprintf(str1, "Error in %s on line %d: pointer not in memlist", file, line);
631                         MemorY_ErroR("free", str1);
632                 } else {
633                         sprintf(str1, "Error in %s on line %d: error in header", file, line);
634                         MemorY_ErroR(name, str1);
635                 }
636         }
637
638         totblock--;
639         /* here a DUMP should happen */
640
641         mem_unlock_thread();
642
643         return(error);
644 }
645
646 /* --------------------------------------------------------------------- */
647 /* local functions                                                       */
648 /* --------------------------------------------------------------------- */
649
650 static void addtail(volatile localListBase *listbase, void *vlink)
651 {
652         struct localLink *link= vlink;
653
654         if (link == 0) return;
655         if (listbase == 0) return;
656
657         link->next = 0;
658         link->prev = listbase->last;
659
660         if (listbase->last) ((struct localLink *)listbase->last)->next = link;
661         if (listbase->first == 0) listbase->first = link;
662         listbase->last = link;
663 }
664
665 static void remlink(volatile localListBase *listbase, void *vlink)
666 {
667         struct localLink *link= vlink;
668
669         if (link == 0) return;
670         if (listbase == 0) return;
671
672         if (link->next) link->next->prev = link->prev;
673         if (link->prev) link->prev->next = link->next;
674
675         if (listbase->last == link) listbase->last = link->prev;
676         if (listbase->first == link) listbase->first = link->next;
677 }
678
679 static void rem_memblock(MemHead *memh)
680 {
681     remlink(membase,&memh->next);
682     if (memh->prev) {
683         if (memh->next) 
684                         MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
685         else 
686                         MEMNEXT(memh->prev)->nextname = NULL;
687     }
688
689     totblock--;
690     mem_in_use -= memh->len;
691    
692     if(memh->mmap) {
693         mmap_in_use -= memh->len;
694         if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail)))
695             printf("Couldn't unmap memory %s\n", memh->name);
696     }
697     else {
698                 if(malloc_debug_memset && memh->len)
699                         memset(memh+1, 255, memh->len);
700         free(memh);
701         }
702 }
703
704 static void MemorY_ErroR(const char *block, const char *error)
705 {
706         print_error("Memoryblock %s: %s\n",block, error);
707 }
708
709 static const char *check_memlist(MemHead *memh)
710 {
711         MemHead *forw,*back,*forwok,*backok;
712         const char *name;
713
714         forw = membase->first;
715         if (forw) forw = MEMNEXT(forw);
716         forwok = 0;
717         while(forw){
718                 if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
719                 forwok = forw;
720                 if (forw->next) forw = MEMNEXT(forw->next);
721                 else forw = 0;
722         }
723
724         back = (MemHead *) membase->last;
725         if (back) back = MEMNEXT(back);
726         backok = 0;
727         while(back){
728                 if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
729                 backok = back;
730                 if (back->prev) back = MEMNEXT(back->prev);
731                 else back = 0;
732         }
733
734         if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
735
736         if (forw == 0 && back == 0){
737                 /* geen foute headers gevonden dan maar op zoek naar memblock*/
738
739                 forw = membase->first;
740                 if (forw) forw = MEMNEXT(forw);
741                 forwok = 0;
742                 while(forw){
743                         if (forw == memh) break;
744                         if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
745                         forwok = forw;
746                         if (forw->next) forw = MEMNEXT(forw->next);
747                         else forw = 0;
748                 }
749                 if (forw == 0) return (0);
750
751                 back = (MemHead *) membase->last;
752                 if (back) back = MEMNEXT(back);
753                 backok = 0;
754                 while(back){
755                         if (back == memh) break;
756                         if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
757                         backok = back;
758                         if (back->prev) back = MEMNEXT(back->prev);
759                         else back = 0;
760                 }
761         }
762
763         if (forwok) name = forwok->nextname;
764         else name = "No name found";
765
766         if (forw == memh){
767                 /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
768                 if (forwok){
769                         if (backok){
770                                 forwok->next = (MemHead *)&backok->next;
771                                 backok->prev = (MemHead *)&forwok->next;
772                                 forwok->nextname = backok->name;
773                         } else{
774                                 forwok->next = 0;
775                                 membase->last = (struct localLink *) &forwok->next; 
776 /*                              membase->last = (struct Link *) &forwok->next; */
777                         }
778                 } else{
779                         if (backok){
780                                 backok->prev = 0;
781                                 membase->first = &backok->next;
782                         } else{
783                                 membase->first = membase->last = 0;
784                         }
785                 }
786         } else{
787                 MemorY_ErroR(name,"Additional error in header");
788                 return("Additional error in header");
789         }
790
791         return(name);
792 }
793
794 uintptr_t MEM_get_peak_memory(void)
795 {
796         uintptr_t _peak_mem;
797
798         mem_lock_thread();
799         _peak_mem = peak_mem;
800         mem_unlock_thread();
801
802         return _peak_mem;
803 }
804
805 void MEM_reset_peak_memory(void)
806 {
807         mem_lock_thread();
808         peak_mem = 0;
809         mem_unlock_thread();
810 }
811
812 uintptr_t MEM_get_memory_in_use(void)
813 {
814         uintptr_t _mem_in_use;
815
816         mem_lock_thread();
817         _mem_in_use= mem_in_use;
818         mem_unlock_thread();
819
820         return _mem_in_use;
821 }
822
823 uintptr_t MEM_get_mapped_memory_in_use(void)
824 {
825         uintptr_t _mmap_in_use;
826
827         mem_lock_thread();
828         _mmap_in_use= mmap_in_use;
829         mem_unlock_thread();
830
831         return _mmap_in_use;
832 }
833
834 int MEM_get_memory_blocks_in_use(void)
835 {
836         int _totblock;
837
838         mem_lock_thread();
839         _totblock= totblock;
840         mem_unlock_thread();
841
842         return _totblock;
843 }
844
845 #ifndef NDEBUG
846 const char *MEM_name_ptr(void *vmemh)
847 {
848         if (vmemh) {
849                 MemHead *memh= vmemh;
850                 memh--;
851                 return memh->name;
852         }
853         else {
854                 return "MEM_name_ptr(NULL)";
855         }
856 }
857 #endif
858
859 /* eof */