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