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