whitespace only, no functional change mixed tabs/spaces --> tabs.
[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 #if defined( __sgi) || defined (__sun) || defined (__sun__) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_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 #ifdef __sgi
369         {
370 #include <fcntl.h>
371
372           int fd;
373           fd = open("/dev/zero", O_RDWR);
374
375           memh= mmap(0, len+sizeof(MemHead)+sizeof(MemTail),
376                         PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
377           close(fd);
378         }
379 #else
380         memh= mmap(NULL, len+sizeof(MemHead)+sizeof(MemTail),
381                    PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
382 #endif
383
384         if(memh!=(MemHead *)-1) {
385                 make_memhead_header(memh, len, str);
386                 memh->mmap= 1;
387                 mmap_in_use += len;
388                 peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem;
389                 mem_unlock_thread();
390 #ifdef DEBUG_MEMCOUNTER
391                 if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL)
392                         memcount_raise("MEM_mapallocN");
393                 memh->_count= _mallocn_count++;
394 #endif
395                 return (++memh);
396         }
397         else {
398                 mem_unlock_thread();
399                 print_error("Mapalloc returns null, fallback to regular malloc: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mmap_in_use);
400                 return MEM_callocN(len, str);
401         }
402 }
403
404 /* Memory statistics print */
405 typedef struct MemPrintBlock {
406         const char *name;
407         uintptr_t len;
408         int items;
409 } MemPrintBlock;
410
411 static int compare_name(const void *p1, const void *p2)
412 {
413         const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
414         const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
415
416         return strcmp(pb1->name, pb2->name);
417 }
418
419 static int compare_len(const void *p1, const void *p2)
420 {
421         const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
422         const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
423
424         if(pb1->len < pb2->len)
425                 return 1;
426         else if(pb1->len == pb2->len)
427                 return 0;
428         else
429                 return -1;
430 }
431
432 void MEM_printmemlist_stats()
433 {
434         MemHead *membl;
435         MemPrintBlock *pb, *printblock;
436         int totpb, a, b;
437
438         mem_lock_thread();
439
440         /* put memory blocks into array */
441         printblock= malloc(sizeof(MemPrintBlock)*totblock);
442
443         pb= printblock;
444         totpb= 0;
445
446         membl = membase->first;
447         if (membl) membl = MEMNEXT(membl);
448
449         while(membl) {
450                 pb->name= membl->name;
451                 pb->len= membl->len;
452                 pb->items= 1;
453
454                 totpb++;
455                 pb++;
456
457                 if(membl->next)
458                         membl= MEMNEXT(membl->next);
459                 else break;
460         }
461
462         /* sort by name and add together blocks with the same name */
463         qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
464         for(a=0, b=0; a<totpb; a++) {
465                 if(a == b) {
466                         continue;
467                 }
468                 else if(strcmp(printblock[a].name, printblock[b].name) == 0) {
469                         printblock[b].len += printblock[a].len;
470                         printblock[b].items++;
471                 }
472                 else {
473                         b++;
474                         memcpy(&printblock[b], &printblock[a], sizeof(MemPrintBlock));
475                 }
476         }
477         totpb= b+1;
478
479         /* sort by length and print */
480         qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
481         printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use/(double)(1024*1024));
482         printf(" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
483         for(a=0, pb=printblock; a<totpb; a++, pb++)
484                 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);
485
486         free(printblock);
487         
488         mem_unlock_thread();
489
490 #if 0 /* GLIBC only */
491         malloc_stats();
492 #endif
493 }
494
495 /* Prints in python syntax for easy */
496 static void MEM_printmemlist_internal( int pydict )
497 {
498         MemHead *membl;
499
500         mem_lock_thread();
501
502         membl = membase->first;
503         if (membl) membl = MEMNEXT(membl);
504         
505         if (pydict) {
506                 print_error("# membase_debug.py\n");
507                 print_error("membase = [\\\n");
508         }
509         while(membl) {
510                 if (pydict) {
511                         fprintf(stderr, "{'len':" SIZET_FORMAT ", 'name':'''%s''', 'pointer':'%p'},\\\n", SIZET_ARG(membl->len), membl->name, (void *)(membl+1));
512                 } else {
513 #ifdef DEBUG_MEMCOUNTER
514                         print_error("%s len: " SIZET_FORMAT " %p, count: %d\n", membl->name, SIZET_ARG(membl->len), membl+1, membl->_count);
515 #else
516                         print_error("%s len: " SIZET_FORMAT " %p\n", membl->name, SIZET_ARG(membl->len), membl+1);
517 #endif
518                 }
519                 if(membl->next)
520                         membl= MEMNEXT(membl->next);
521                 else break;
522         }
523         if (pydict) {
524                 fprintf(stderr, "]\n\n");
525                 fprintf(stderr,
526 "mb_userinfo = {}\n"
527 "totmem = 0\n"
528 "for mb_item in membase:\n"
529 "\tmb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
530 "\tmb_item_user_size[0] += 1 # Add a user\n"
531 "\tmb_item_user_size[1] += mb_item['len'] # Increment the size\n"
532 "\ttotmem += mb_item['len']\n"
533 "print '(membase) items:', len(membase), '| unique-names:', len(mb_userinfo), '| total-mem:', totmem\n"
534 "mb_userinfo_sort = mb_userinfo.items()\n"
535 "for sort_name, sort_func in (('size', lambda a: -a[1][1]), ('users', lambda a: -a[1][0]), ('name', lambda a: a[0])):\n"
536 "\tprint '\\nSorting by:', sort_name\n"
537 "\tmb_userinfo_sort.sort(key = sort_func)\n"
538 "\tfor item in mb_userinfo_sort:\n"
539 "\t\tprint 'name:%%s, users:%%i, len:%%i' %% (item[0], item[1][0], item[1][1])\n"
540                 );
541         }
542         
543         mem_unlock_thread();
544 }
545
546 void MEM_callbackmemlist(void (*func)(void*)) {
547         MemHead *membl;
548
549         mem_lock_thread();
550
551         membl = membase->first;
552         if (membl) membl = MEMNEXT(membl);
553
554         while(membl) {
555                 func(membl+1);
556                 if(membl->next)
557                         membl= MEMNEXT(membl->next);
558                 else break;
559         }
560
561         mem_unlock_thread();
562 }
563
564 short MEM_testN(void *vmemh) {
565         MemHead *membl;
566
567         mem_lock_thread();
568
569         membl = membase->first;
570         if (membl) membl = MEMNEXT(membl);
571
572         while(membl) {
573                 if (vmemh == membl+1) {
574                         mem_unlock_thread();
575                         return 1;
576                 }
577
578                 if(membl->next)
579                         membl= MEMNEXT(membl->next);
580                 else break;
581         }
582
583         mem_unlock_thread();
584
585         print_error("Memoryblock %p: pointer not in memlist\n", vmemh);
586         return 0;
587 }
588
589 void MEM_printmemlist( void ) {
590         MEM_printmemlist_internal(0);
591 }
592 void MEM_printmemlist_pydict( void ) {
593         MEM_printmemlist_internal(1);
594 }
595
596 short MEM_freeN(void *vmemh)            /* anders compileertie niet meer */
597 {
598         short error = 0;
599         MemTail *memt;
600         MemHead *memh= vmemh;
601         const char *name;
602
603         if (memh == NULL){
604                 MemorY_ErroR("free","attempt to free NULL pointer");
605                 /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
606                 return(-1);
607         }
608
609         if(sizeof(intptr_t)==8) {
610                 if (((intptr_t) memh) & 0x7) {
611                         MemorY_ErroR("free","attempt to free illegal pointer");
612                         return(-1);
613                 }
614         }
615         else {
616                 if (((intptr_t) memh) & 0x3) {
617                         MemorY_ErroR("free","attempt to free illegal pointer");
618                         return(-1);
619                 }
620         }
621         
622         memh--;
623         if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
624                 MemorY_ErroR(memh->name,"double free");
625                 return(-1);
626         }
627
628         mem_lock_thread();
629         if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
630                 memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len);
631                 if (memt->tag3 == MEMTAG3){
632                         
633                         memh->tag1 = MEMFREE;
634                         memh->tag2 = MEMFREE;
635                         memt->tag3 = MEMFREE;
636                         /* after tags !!! */
637                         rem_memblock(memh);
638
639                         mem_unlock_thread();
640                         
641                         return(0);
642                 }
643                 error = 2;
644                 MemorY_ErroR(memh->name,"end corrupt");
645                 name = check_memlist(memh);
646                 if (name != NULL){
647                         if (name != memh->name) MemorY_ErroR(name,"is also corrupt");
648                 }
649         } else{
650                 error = -1;
651                 name = check_memlist(memh);
652                 if (name == NULL)
653                         MemorY_ErroR("free","pointer not in memlist");
654                 else
655                         MemorY_ErroR(name,"error in header");
656         }
657
658         totblock--;
659         /* here a DUMP should happen */
660
661         mem_unlock_thread();
662
663         return(error);
664 }
665
666 /* --------------------------------------------------------------------- */
667 /* local functions                                                       */
668 /* --------------------------------------------------------------------- */
669
670 static void addtail(volatile localListBase *listbase, void *vlink)
671 {
672         struct localLink *link= vlink;
673
674         if (link == NULL) return;
675         if (listbase == NULL) return;
676
677         link->next = NULL;
678         link->prev = listbase->last;
679
680         if (listbase->last) ((struct localLink *)listbase->last)->next = link;
681         if (listbase->first == NULL) listbase->first = link;
682         listbase->last = link;
683 }
684
685 static void remlink(volatile localListBase *listbase, void *vlink)
686 {
687         struct localLink *link= vlink;
688
689         if (link == NULL) return;
690         if (listbase == NULL) return;
691
692         if (link->next) link->next->prev = link->prev;
693         if (link->prev) link->prev->next = link->next;
694
695         if (listbase->last == link) listbase->last = link->prev;
696         if (listbase->first == link) listbase->first = link->next;
697 }
698
699 static void rem_memblock(MemHead *memh)
700 {
701         remlink(membase,&memh->next);
702         if (memh->prev) {
703                 if (memh->next)
704                         MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
705                 else
706                         MEMNEXT(memh->prev)->nextname = NULL;
707         }
708
709         totblock--;
710         mem_in_use -= memh->len;
711
712         if(memh->mmap) {
713                 mmap_in_use -= memh->len;
714                 if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail)))
715                         printf("Couldn't unmap memory %s\n", memh->name);
716         }
717         else {
718                 if(malloc_debug_memset && memh->len)
719                         memset(memh+1, 255, memh->len);
720                 free(memh);
721         }
722 }
723
724 static void MemorY_ErroR(const char *block, const char *error)
725 {
726         print_error("Memoryblock %s: %s\n",block, error);
727 }
728
729 static const char *check_memlist(MemHead *memh)
730 {
731         MemHead *forw,*back,*forwok,*backok;
732         const char *name;
733
734         forw = membase->first;
735         if (forw) forw = MEMNEXT(forw);
736         forwok = NULL;
737         while(forw){
738                 if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
739                 forwok = forw;
740                 if (forw->next) forw = MEMNEXT(forw->next);
741                 else forw = NULL;
742         }
743
744         back = (MemHead *) membase->last;
745         if (back) back = MEMNEXT(back);
746         backok = NULL;
747         while(back){
748                 if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
749                 backok = back;
750                 if (back->prev) back = MEMNEXT(back->prev);
751                 else back = NULL;
752         }
753
754         if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
755
756         if (forw == NULL && back == NULL){
757                 /* geen foute headers gevonden dan maar op zoek naar memblock*/
758
759                 forw = membase->first;
760                 if (forw) forw = MEMNEXT(forw);
761                 forwok = NULL;
762                 while(forw){
763                         if (forw == memh) break;
764                         if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
765                         forwok = forw;
766                         if (forw->next) forw = MEMNEXT(forw->next);
767                         else forw = NULL;
768                 }
769                 if (forw == NULL) return NULL;
770
771                 back = (MemHead *) membase->last;
772                 if (back) back = MEMNEXT(back);
773                 backok = NULL;
774                 while(back){
775                         if (back == memh) break;
776                         if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
777                         backok = back;
778                         if (back->prev) back = MEMNEXT(back->prev);
779                         else back = NULL;
780                 }
781         }
782
783         if (forwok) name = forwok->nextname;
784         else name = "No name found";
785
786         if (forw == memh){
787                 /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
788                 if (forwok){
789                         if (backok){
790                                 forwok->next = (MemHead *)&backok->next;
791                                 backok->prev = (MemHead *)&forwok->next;
792                                 forwok->nextname = backok->name;
793                         } else{
794                                 forwok->next = NULL;
795                                 membase->last = (struct localLink *) &forwok->next; 
796 /*                              membase->last = (struct Link *) &forwok->next; */
797                         }
798                 } else{
799                         if (backok){
800                                 backok->prev = NULL;
801                                 membase->first = &backok->next;
802                         } else{
803                                 membase->first = membase->last = NULL;
804                         }
805                 }
806         } else{
807                 MemorY_ErroR(name,"Additional error in header");
808                 return("Additional error in header");
809         }
810
811         return(name);
812 }
813
814 uintptr_t MEM_get_peak_memory(void)
815 {
816         uintptr_t _peak_mem;
817
818         mem_lock_thread();
819         _peak_mem = peak_mem;
820         mem_unlock_thread();
821
822         return _peak_mem;
823 }
824
825 void MEM_reset_peak_memory(void)
826 {
827         mem_lock_thread();
828         peak_mem = 0;
829         mem_unlock_thread();
830 }
831
832 uintptr_t MEM_get_memory_in_use(void)
833 {
834         uintptr_t _mem_in_use;
835
836         mem_lock_thread();
837         _mem_in_use= mem_in_use;
838         mem_unlock_thread();
839
840         return _mem_in_use;
841 }
842
843 uintptr_t MEM_get_mapped_memory_in_use(void)
844 {
845         uintptr_t _mmap_in_use;
846
847         mem_lock_thread();
848         _mmap_in_use= mmap_in_use;
849         mem_unlock_thread();
850
851         return _mmap_in_use;
852 }
853
854 int MEM_get_memory_blocks_in_use(void)
855 {
856         int _totblock;
857
858         mem_lock_thread();
859         _totblock= totblock;
860         mem_unlock_thread();
861
862         return _totblock;
863 }
864
865 #ifndef NDEBUG
866 const char *MEM_name_ptr(void *vmemh)
867 {
868         if (vmemh) {
869                 MemHead *memh= vmemh;
870                 memh--;
871                 return memh->name;
872         }
873         else {
874                 return "MEM_name_ptr(NULL)";
875         }
876 }
877 #endif
878
879 /* eof */