removed the OBJ export recent commit, didnt realize BMesh had its own OBJ exporter.
[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., 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 /** \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(void)
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 == NULL) 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 = NULL;
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 NULL;
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(NULL, 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 != NULL){
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
630                 if (name == 0) {
631                         sprintf(str1, "Error in %s on line %d: pointer not in memlist", file, line);
632                         MemorY_ErroR("free", str1);
633                 } else {
634                         sprintf(str1, "Error in %s on line %d: error in header", file, line);
635                         MemorY_ErroR(name, str1);
636                 }
637         }
638
639         totblock--;
640         /* here a DUMP should happen */
641
642         mem_unlock_thread();
643
644         return(error);
645 }
646
647 /* --------------------------------------------------------------------- */
648 /* local functions                                                       */
649 /* --------------------------------------------------------------------- */
650
651 static void addtail(volatile localListBase *listbase, void *vlink)
652 {
653         struct localLink *link= vlink;
654
655         if (link == NULL) return;
656         if (listbase == NULL) return;
657
658         link->next = NULL;
659         link->prev = listbase->last;
660
661         if (listbase->last) ((struct localLink *)listbase->last)->next = link;
662         if (listbase->first == NULL) listbase->first = link;
663         listbase->last = link;
664 }
665
666 static void remlink(volatile localListBase *listbase, void *vlink)
667 {
668         struct localLink *link= vlink;
669
670         if (link == NULL) return;
671         if (listbase == NULL) return;
672
673         if (link->next) link->next->prev = link->prev;
674         if (link->prev) link->prev->next = link->next;
675
676         if (listbase->last == link) listbase->last = link->prev;
677         if (listbase->first == link) listbase->first = link->next;
678 }
679
680 static void rem_memblock(MemHead *memh)
681 {
682         remlink(membase,&memh->next);
683         if (memh->prev) {
684                 if (memh->next)
685                         MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
686                 else
687                         MEMNEXT(memh->prev)->nextname = NULL;
688         }
689
690         totblock--;
691         mem_in_use -= memh->len;
692
693         if(memh->mmap) {
694                 mmap_in_use -= memh->len;
695                 if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail)))
696                         printf("Couldn't unmap memory %s\n", memh->name);
697         }
698         else {
699                 if(malloc_debug_memset && memh->len)
700                         memset(memh+1, 255, memh->len);
701                 free(memh);
702         }
703 }
704
705 static void MemorY_ErroR(const char *block, const char *error)
706 {
707         print_error("Memoryblock %s: %s\n",block, error);
708 }
709
710 static const char *check_memlist(MemHead *memh)
711 {
712         MemHead *forw,*back,*forwok,*backok;
713         const char *name;
714
715         forw = membase->first;
716         if (forw) forw = MEMNEXT(forw);
717         forwok = NULL;
718         while(forw){
719                 if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
720                 forwok = forw;
721                 if (forw->next) forw = MEMNEXT(forw->next);
722                 else forw = NULL;
723         }
724
725         back = (MemHead *) membase->last;
726         if (back) back = MEMNEXT(back);
727         backok = NULL;
728         while(back){
729                 if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
730                 backok = back;
731                 if (back->prev) back = MEMNEXT(back->prev);
732                 else back = NULL;
733         }
734
735         if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
736
737         if (forw == NULL && back == NULL){
738                 /* geen foute headers gevonden dan maar op zoek naar memblock*/
739
740                 forw = membase->first;
741                 if (forw) forw = MEMNEXT(forw);
742                 forwok = NULL;
743                 while(forw){
744                         if (forw == memh) break;
745                         if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
746                         forwok = forw;
747                         if (forw->next) forw = MEMNEXT(forw->next);
748                         else forw = NULL;
749                 }
750                 if (forw == NULL) return NULL;
751
752                 back = (MemHead *) membase->last;
753                 if (back) back = MEMNEXT(back);
754                 backok = NULL;
755                 while(back){
756                         if (back == memh) break;
757                         if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
758                         backok = back;
759                         if (back->prev) back = MEMNEXT(back->prev);
760                         else back = NULL;
761                 }
762         }
763
764         if (forwok) name = forwok->nextname;
765         else name = "No name found";
766
767         if (forw == memh){
768                 /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
769                 if (forwok){
770                         if (backok){
771                                 forwok->next = (MemHead *)&backok->next;
772                                 backok->prev = (MemHead *)&forwok->next;
773                                 forwok->nextname = backok->name;
774                         } else{
775                                 forwok->next = NULL;
776                                 membase->last = (struct localLink *) &forwok->next;
777 /*                              membase->last = (struct Link *) &forwok->next; */
778                         }
779                 } else{
780                         if (backok){
781                                 backok->prev = NULL;
782                                 membase->first = &backok->next;
783                         } else{
784                                 membase->first = membase->last = NULL;
785                         }
786                 }
787         } else{
788                 MemorY_ErroR(name,"Additional error in header");
789                 return("Additional error in header");
790         }
791
792         return(name);
793 }
794
795 uintptr_t MEM_get_peak_memory(void)
796 {
797         uintptr_t _peak_mem;
798
799         mem_lock_thread();
800         _peak_mem = peak_mem;
801         mem_unlock_thread();
802
803         return _peak_mem;
804 }
805
806 void MEM_reset_peak_memory(void)
807 {
808         mem_lock_thread();
809         peak_mem = 0;
810         mem_unlock_thread();
811 }
812
813 uintptr_t MEM_get_memory_in_use(void)
814 {
815         uintptr_t _mem_in_use;
816
817         mem_lock_thread();
818         _mem_in_use= mem_in_use;
819         mem_unlock_thread();
820
821         return _mem_in_use;
822 }
823
824 uintptr_t MEM_get_mapped_memory_in_use(void)
825 {
826         uintptr_t _mmap_in_use;
827
828         mem_lock_thread();
829         _mmap_in_use= mmap_in_use;
830         mem_unlock_thread();
831
832         return _mmap_in_use;
833 }
834
835 int MEM_get_memory_blocks_in_use(void)
836 {
837         int _totblock;
838
839         mem_lock_thread();
840         _totblock= totblock;
841         mem_unlock_thread();
842
843         return _totblock;
844 }
845
846 #ifndef NDEBUG
847 const char *MEM_name_ptr(void *vmemh)
848 {
849         if (vmemh) {
850                 MemHead *memh= vmemh;
851                 memh--;
852                 return memh->name;
853         }
854         else {
855                 return "MEM_name_ptr(NULL)";
856         }
857 }
858 #endif
859
860 /* eof */