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