Blender V2.61 - r43446

mallocn.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00039 #include <stdlib.h>
00040 #include <string.h> /* memcpy */
00041 #include <stdarg.h>
00042 #include <sys/types.h>
00043 /* Blame Microsoft for LLP64 and no inttypes.h, quick workaround needed: */
00044 #if defined(WIN64)
00045 #define SIZET_FORMAT "%I64u"
00046 #define SIZET_ARG(a) ((unsigned long long)(a))
00047 #else
00048 #define SIZET_FORMAT "%lu"
00049 #define SIZET_ARG(a) ((unsigned long)(a))
00050 #endif
00051 
00052 /* mmap exception */
00053 #if defined(WIN32)
00054 #include "mmap_win.h"
00055 #else
00056 #include <sys/mman.h>
00057 #endif
00058 
00059 #include "MEM_guardedalloc.h"
00060 
00061 /* Only for debugging:
00062  * lets you count the allocations so as to find the allocator of unfreed memory
00063  * in situations where the leak is predictable */
00064 
00065 // #define DEBUG_MEMCOUNTER
00066 
00067 #ifdef DEBUG_MEMCOUNTER
00068 #define DEBUG_MEMCOUNTER_ERROR_VAL 0 /* set this to the value that isnt being freed */
00069 static int _mallocn_count = 0;
00070 
00071 /* breakpoint here */
00072 static void memcount_raise(const char *name)
00073 {
00074     fprintf(stderr, "%s: memcount-leak, %d\n", name, _mallocn_count);
00075 }
00076 #endif
00077 
00078 /* --------------------------------------------------------------------- */
00079 /* Data definition                                                       */
00080 /* --------------------------------------------------------------------- */
00081 /* all memory chunks are put in linked lists */
00082 typedef struct localLink
00083 {
00084     struct localLink *next,*prev;
00085 } localLink;
00086 
00087 typedef struct localListBase 
00088 {
00089     void *first, *last;
00090 } localListBase;
00091 
00092     /* note: keep this struct aligned (e.g., irix/gcc) - Hos */
00093 typedef struct MemHead {
00094     int tag1;
00095     size_t len;
00096     struct MemHead *next,*prev;
00097     const char * name;
00098     const char * nextname;
00099     int tag2;
00100     int mmap;   /* if true, memory was mmapped */
00101 #ifdef DEBUG_MEMCOUNTER
00102     int _count;
00103 #endif
00104 } MemHead;
00105 
00106 typedef struct MemTail {
00107     int tag3, pad;
00108 } MemTail;
00109 
00110 
00111 /* --------------------------------------------------------------------- */
00112 /* local functions                                                       */
00113 /* --------------------------------------------------------------------- */
00114 
00115 static void addtail(volatile localListBase *listbase, void *vlink);
00116 static void remlink(volatile localListBase *listbase, void *vlink);
00117 static void rem_memblock(MemHead *memh);
00118 static void MemorY_ErroR(const char *block, const char *error);
00119 static const char *check_memlist(MemHead *memh);
00120 
00121 /* --------------------------------------------------------------------- */
00122 /* locally used defines                                                  */
00123 /* --------------------------------------------------------------------- */
00124 
00125 #ifdef __BIG_ENDIAN__
00126 #  define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
00127 #else
00128 #  define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
00129 #endif
00130 
00131 #define MEMTAG1 MAKE_ID('M', 'E', 'M', 'O')
00132 #define MEMTAG2 MAKE_ID('R', 'Y', 'B', 'L')
00133 #define MEMTAG3 MAKE_ID('O', 'C', 'K', '!')
00134 #define MEMFREE MAKE_ID('F', 'R', 'E', 'E')
00135 
00136 #define MEMNEXT(x) ((MemHead *)(((char *) x) - ((char *) & (((MemHead *)0)->next))))
00137     
00138 /* --------------------------------------------------------------------- */
00139 /* vars                                                                  */
00140 /* --------------------------------------------------------------------- */
00141     
00142 
00143 static volatile int totblock= 0;
00144 static volatile uintptr_t mem_in_use= 0, mmap_in_use= 0, peak_mem = 0;
00145 
00146 static volatile struct localListBase _membase;
00147 static volatile struct localListBase *membase = &_membase;
00148 static void (*error_callback)(const char *) = NULL;
00149 static void (*thread_lock_callback)(void) = NULL;
00150 static void (*thread_unlock_callback)(void) = NULL;
00151 
00152 static int malloc_debug_memset= 0;
00153 
00154 #ifdef malloc
00155 #undef malloc
00156 #endif
00157 
00158 #ifdef calloc
00159 #undef calloc
00160 #endif
00161 
00162 #ifdef free
00163 #undef free
00164 #endif
00165 
00166 
00167 /* --------------------------------------------------------------------- */
00168 /* implementation                                                        */
00169 /* --------------------------------------------------------------------- */
00170 
00171 static void print_error(const char *str, ...)
00172 {
00173     char buf[512];
00174     va_list ap;
00175 
00176     va_start(ap, str);
00177     vsnprintf(buf, sizeof(buf), str, ap);
00178     va_end(ap);
00179     buf[sizeof(buf) - 1] = '\0';
00180 
00181     if (error_callback) error_callback(buf);
00182 }
00183 
00184 static void mem_lock_thread(void)
00185 {
00186     if (thread_lock_callback)
00187         thread_lock_callback();
00188 }
00189 
00190 static void mem_unlock_thread(void)
00191 {
00192     if (thread_unlock_callback)
00193         thread_unlock_callback();
00194 }
00195 
00196 int MEM_check_memory_integrity(void)
00197 {
00198     const char* err_val = NULL;
00199     MemHead* listend;
00200     /* check_memlist starts from the front, and runs until it finds
00201      * the requested chunk. For this test, that's the last one. */
00202     listend = membase->last;
00203     
00204     err_val = check_memlist(listend);
00205 
00206     if (err_val == NULL) return 0;
00207     return 1;
00208 }
00209 
00210 
00211 void MEM_set_error_callback(void (*func)(const char *))
00212 {
00213     error_callback = func;
00214 }
00215 
00216 void MEM_set_lock_callback(void (*lock)(void), void (*unlock)(void))
00217 {
00218     thread_lock_callback = lock;
00219     thread_unlock_callback = unlock;
00220 }
00221 
00222 void MEM_set_memory_debug(void)
00223 {
00224     malloc_debug_memset= 1;
00225 }
00226 
00227 size_t MEM_allocN_len(void *vmemh)
00228 {
00229     if (vmemh) {
00230         MemHead *memh= vmemh;
00231     
00232         memh--;
00233         return memh->len;
00234     } else
00235         return 0;
00236 }
00237 
00238 void *MEM_dupallocN(void *vmemh)
00239 {
00240     void *newp= NULL;
00241     
00242     if (vmemh) {
00243         MemHead *memh= vmemh;
00244         memh--;
00245         
00246         if(memh->mmap)
00247             newp= MEM_mapallocN(memh->len, "dupli_mapalloc");
00248         else
00249             newp= MEM_mallocN(memh->len, "dupli_alloc");
00250 
00251         if (newp == NULL) return NULL;
00252 
00253         memcpy(newp, vmemh, memh->len);
00254     }
00255 
00256     return newp;
00257 }
00258 
00259 void *MEM_reallocN(void *vmemh, size_t len)
00260 {
00261     void *newp= NULL;
00262     
00263     if (vmemh) {
00264         MemHead *memh= vmemh;
00265         memh--;
00266 
00267         newp= MEM_mallocN(len, memh->name);
00268         if(newp) {
00269             if(len < memh->len)
00270                 memcpy(newp, vmemh, len);
00271             else
00272                 memcpy(newp, vmemh, memh->len);
00273         }
00274 
00275         MEM_freeN(vmemh);
00276     }
00277 
00278     return newp;
00279 }
00280 
00281 static void make_memhead_header(MemHead *memh, size_t len, const char *str)
00282 {
00283     MemTail *memt;
00284     
00285     memh->tag1 = MEMTAG1;
00286     memh->name = str;
00287     memh->nextname = NULL;
00288     memh->len = len;
00289     memh->mmap = 0;
00290     memh->tag2 = MEMTAG2;
00291     
00292     memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len);
00293     memt->tag3 = MEMTAG3;
00294     
00295     addtail(membase,&memh->next);
00296     if (memh->next) memh->nextname = MEMNEXT(memh->next)->name;
00297     
00298     totblock++;
00299     mem_in_use += len;
00300 
00301     peak_mem = mem_in_use > peak_mem ? mem_in_use : peak_mem;
00302 }
00303 
00304 void *MEM_mallocN(size_t len, const char *str)
00305 {
00306     MemHead *memh;
00307 
00308     mem_lock_thread();
00309 
00310     len = (len + 3 ) & ~3;  /* allocate in units of 4 */
00311     
00312     memh= (MemHead *)malloc(len+sizeof(MemHead)+sizeof(MemTail));
00313 
00314     if(memh) {
00315         make_memhead_header(memh, len, str);
00316         mem_unlock_thread();
00317         if(malloc_debug_memset && len)
00318             memset(memh+1, 255, len);
00319 
00320 #ifdef DEBUG_MEMCOUNTER
00321         if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL)
00322             memcount_raise("MEM_mallocN");
00323         memh->_count= _mallocn_count++;
00324 #endif
00325         return (++memh);
00326     }
00327     mem_unlock_thread();
00328     print_error("Malloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use);
00329     return NULL;
00330 }
00331 
00332 void *MEM_callocN(size_t len, const char *str)
00333 {
00334     MemHead *memh;
00335 
00336     mem_lock_thread();
00337 
00338     len = (len + 3 ) & ~3;  /* allocate in units of 4 */
00339 
00340     memh= (MemHead *)calloc(len+sizeof(MemHead)+sizeof(MemTail),1);
00341 
00342     if(memh) {
00343         make_memhead_header(memh, len, str);
00344         mem_unlock_thread();
00345 #ifdef DEBUG_MEMCOUNTER
00346         if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL)
00347             memcount_raise("MEM_callocN");
00348         memh->_count= _mallocn_count++;
00349 #endif
00350         return (++memh);
00351     }
00352     mem_unlock_thread();
00353     print_error("Calloc returns null: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mem_in_use);
00354     return NULL;
00355 }
00356 
00357 /* note; mmap returns zero'd memory */
00358 void *MEM_mapallocN(size_t len, const char *str)
00359 {
00360     MemHead *memh;
00361 
00362     mem_lock_thread();
00363     
00364     len = (len + 3 ) & ~3;  /* allocate in units of 4 */
00365 
00366     memh= mmap(NULL, len+sizeof(MemHead)+sizeof(MemTail),
00367             PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
00368 
00369     if(memh!=(MemHead *)-1) {
00370         make_memhead_header(memh, len, str);
00371         memh->mmap= 1;
00372         mmap_in_use += len;
00373         peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem;
00374         mem_unlock_thread();
00375 #ifdef DEBUG_MEMCOUNTER
00376         if(_mallocn_count==DEBUG_MEMCOUNTER_ERROR_VAL)
00377             memcount_raise("MEM_mapallocN");
00378         memh->_count= _mallocn_count++;
00379 #endif
00380         return (++memh);
00381     }
00382     else {
00383         mem_unlock_thread();
00384         print_error("Mapalloc returns null, fallback to regular malloc: len=" SIZET_FORMAT " in %s, total %u\n", SIZET_ARG(len), str, mmap_in_use);
00385         return MEM_callocN(len, str);
00386     }
00387 }
00388 
00389 /* Memory statistics print */
00390 typedef struct MemPrintBlock {
00391     const char *name;
00392     uintptr_t len;
00393     int items;
00394 } MemPrintBlock;
00395 
00396 static int compare_name(const void *p1, const void *p2)
00397 {
00398     const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
00399     const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
00400 
00401     return strcmp(pb1->name, pb2->name);
00402 }
00403 
00404 static int compare_len(const void *p1, const void *p2)
00405 {
00406     const MemPrintBlock *pb1= (const MemPrintBlock*)p1;
00407     const MemPrintBlock *pb2= (const MemPrintBlock*)p2;
00408 
00409     if(pb1->len < pb2->len)
00410         return 1;
00411     else if(pb1->len == pb2->len)
00412         return 0;
00413     else
00414         return -1;
00415 }
00416 
00417 void MEM_printmemlist_stats(void)
00418 {
00419     MemHead *membl;
00420     MemPrintBlock *pb, *printblock;
00421     int totpb, a, b;
00422 
00423     mem_lock_thread();
00424 
00425     /* put memory blocks into array */
00426     printblock= malloc(sizeof(MemPrintBlock)*totblock);
00427 
00428     pb= printblock;
00429     totpb= 0;
00430 
00431     membl = membase->first;
00432     if (membl) membl = MEMNEXT(membl);
00433 
00434     while(membl) {
00435         pb->name= membl->name;
00436         pb->len= membl->len;
00437         pb->items= 1;
00438 
00439         totpb++;
00440         pb++;
00441 
00442         if(membl->next)
00443             membl= MEMNEXT(membl->next);
00444         else break;
00445     }
00446 
00447     /* sort by name and add together blocks with the same name */
00448     qsort(printblock, totpb, sizeof(MemPrintBlock), compare_name);
00449     for(a=0, b=0; a<totpb; a++) {
00450         if(a == b) {
00451             continue;
00452         }
00453         else if(strcmp(printblock[a].name, printblock[b].name) == 0) {
00454             printblock[b].len += printblock[a].len;
00455             printblock[b].items++;
00456         }
00457         else {
00458             b++;
00459             memcpy(&printblock[b], &printblock[a], sizeof(MemPrintBlock));
00460         }
00461     }
00462     totpb= b+1;
00463 
00464     /* sort by length and print */
00465     qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
00466     printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use/(double)(1024*1024));
00467     printf(" ITEMS TOTAL-MiB AVERAGE-KiB TYPE\n");
00468     for(a=0, pb=printblock; a<totpb; a++, pb++)
00469         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);
00470 
00471     free(printblock);
00472     
00473     mem_unlock_thread();
00474 
00475 #if 0 /* GLIBC only */
00476     malloc_stats();
00477 #endif
00478 }
00479 
00480 /* Prints in python syntax for easy */
00481 static void MEM_printmemlist_internal( int pydict )
00482 {
00483     MemHead *membl;
00484 
00485     mem_lock_thread();
00486 
00487     membl = membase->first;
00488     if (membl) membl = MEMNEXT(membl);
00489     
00490     if (pydict) {
00491         print_error("# membase_debug.py\n");
00492         print_error("membase = [\\\n");
00493     }
00494     while(membl) {
00495         if (pydict) {
00496             fprintf(stderr, "{'len':" SIZET_FORMAT ", 'name':'''%s''', 'pointer':'%p'},\\\n", SIZET_ARG(membl->len), membl->name, (void *)(membl+1));
00497         } else {
00498 #ifdef DEBUG_MEMCOUNTER
00499             print_error("%s len: " SIZET_FORMAT " %p, count: %d\n", membl->name, SIZET_ARG(membl->len), membl+1, membl->_count);
00500 #else
00501             print_error("%s len: " SIZET_FORMAT " %p\n", membl->name, SIZET_ARG(membl->len), membl+1);
00502 #endif
00503         }
00504         if(membl->next)
00505             membl= MEMNEXT(membl->next);
00506         else break;
00507     }
00508     if (pydict) {
00509         fprintf(stderr, "]\n\n");
00510         fprintf(stderr,
00511 "mb_userinfo = {}\n"
00512 "totmem = 0\n"
00513 "for mb_item in membase:\n"
00514 "\tmb_item_user_size = mb_userinfo.setdefault(mb_item['name'], [0,0])\n"
00515 "\tmb_item_user_size[0] += 1 # Add a user\n"
00516 "\tmb_item_user_size[1] += mb_item['len'] # Increment the size\n"
00517 "\ttotmem += mb_item['len']\n"
00518 "print '(membase) items:', len(membase), '| unique-names:', len(mb_userinfo), '| total-mem:', totmem\n"
00519 "mb_userinfo_sort = mb_userinfo.items()\n"
00520 "for sort_name, sort_func in (('size', lambda a: -a[1][1]), ('users', lambda a: -a[1][0]), ('name', lambda a: a[0])):\n"
00521 "\tprint '\\nSorting by:', sort_name\n"
00522 "\tmb_userinfo_sort.sort(key = sort_func)\n"
00523 "\tfor item in mb_userinfo_sort:\n"
00524 "\t\tprint 'name:%%s, users:%%i, len:%%i' %% (item[0], item[1][0], item[1][1])\n"
00525         );
00526     }
00527     
00528     mem_unlock_thread();
00529 }
00530 
00531 void MEM_callbackmemlist(void (*func)(void*)) {
00532     MemHead *membl;
00533 
00534     mem_lock_thread();
00535 
00536     membl = membase->first;
00537     if (membl) membl = MEMNEXT(membl);
00538 
00539     while(membl) {
00540         func(membl+1);
00541         if(membl->next)
00542             membl= MEMNEXT(membl->next);
00543         else break;
00544     }
00545 
00546     mem_unlock_thread();
00547 }
00548 
00549 short MEM_testN(void *vmemh) {
00550     MemHead *membl;
00551 
00552     mem_lock_thread();
00553 
00554     membl = membase->first;
00555     if (membl) membl = MEMNEXT(membl);
00556 
00557     while(membl) {
00558         if (vmemh == membl+1) {
00559             mem_unlock_thread();
00560             return 1;
00561         }
00562 
00563         if(membl->next)
00564             membl= MEMNEXT(membl->next);
00565         else break;
00566     }
00567 
00568     mem_unlock_thread();
00569 
00570     print_error("Memoryblock %p: pointer not in memlist\n", vmemh);
00571     return 0;
00572 }
00573 
00574 void MEM_printmemlist( void ) {
00575     MEM_printmemlist_internal(0);
00576 }
00577 void MEM_printmemlist_pydict( void ) {
00578     MEM_printmemlist_internal(1);
00579 }
00580 
00581 short MEM_freeN(void *vmemh)        /* anders compileertie niet meer */
00582 {
00583     short error = 0;
00584     MemTail *memt;
00585     MemHead *memh= vmemh;
00586     const char *name;
00587 
00588     if (memh == NULL){
00589         MemorY_ErroR("free","attempt to free NULL pointer");
00590         /* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
00591         return(-1);
00592     }
00593 
00594     if(sizeof(intptr_t)==8) {
00595         if (((intptr_t) memh) & 0x7) {
00596             MemorY_ErroR("free","attempt to free illegal pointer");
00597             return(-1);
00598         }
00599     }
00600     else {
00601         if (((intptr_t) memh) & 0x3) {
00602             MemorY_ErroR("free","attempt to free illegal pointer");
00603             return(-1);
00604         }
00605     }
00606     
00607     memh--;
00608     if(memh->tag1 == MEMFREE && memh->tag2 == MEMFREE) {
00609         MemorY_ErroR(memh->name,"double free");
00610         return(-1);
00611     }
00612 
00613     mem_lock_thread();
00614     if ((memh->tag1 == MEMTAG1) && (memh->tag2 == MEMTAG2) && ((memh->len & 0x3) == 0)) {
00615         memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + memh->len);
00616         if (memt->tag3 == MEMTAG3){
00617             
00618             memh->tag1 = MEMFREE;
00619             memh->tag2 = MEMFREE;
00620             memt->tag3 = MEMFREE;
00621             /* after tags !!! */
00622             rem_memblock(memh);
00623 
00624             mem_unlock_thread();
00625             
00626             return(0);
00627         }
00628         error = 2;
00629         MemorY_ErroR(memh->name,"end corrupt");
00630         name = check_memlist(memh);
00631         if (name != NULL){
00632             if (name != memh->name) MemorY_ErroR(name,"is also corrupt");
00633         }
00634     } else{
00635         error = -1;
00636         name = check_memlist(memh);
00637         if (name == NULL)
00638             MemorY_ErroR("free","pointer not in memlist");
00639         else
00640             MemorY_ErroR(name,"error in header");
00641     }
00642 
00643     totblock--;
00644     /* here a DUMP should happen */
00645 
00646     mem_unlock_thread();
00647 
00648     return(error);
00649 }
00650 
00651 /* --------------------------------------------------------------------- */
00652 /* local functions                                                       */
00653 /* --------------------------------------------------------------------- */
00654 
00655 static void addtail(volatile localListBase *listbase, void *vlink)
00656 {
00657     struct localLink *link= vlink;
00658 
00659     if (link == NULL) return;
00660     if (listbase == NULL) return;
00661 
00662     link->next = NULL;
00663     link->prev = listbase->last;
00664 
00665     if (listbase->last) ((struct localLink *)listbase->last)->next = link;
00666     if (listbase->first == NULL) listbase->first = link;
00667     listbase->last = link;
00668 }
00669 
00670 static void remlink(volatile localListBase *listbase, void *vlink)
00671 {
00672     struct localLink *link= vlink;
00673 
00674     if (link == NULL) return;
00675     if (listbase == NULL) return;
00676 
00677     if (link->next) link->next->prev = link->prev;
00678     if (link->prev) link->prev->next = link->next;
00679 
00680     if (listbase->last == link) listbase->last = link->prev;
00681     if (listbase->first == link) listbase->first = link->next;
00682 }
00683 
00684 static void rem_memblock(MemHead *memh)
00685 {
00686     remlink(membase,&memh->next);
00687     if (memh->prev) {
00688         if (memh->next)
00689             MEMNEXT(memh->prev)->nextname = MEMNEXT(memh->next)->name;
00690         else
00691             MEMNEXT(memh->prev)->nextname = NULL;
00692     }
00693 
00694     totblock--;
00695     mem_in_use -= memh->len;
00696 
00697     if(memh->mmap) {
00698         mmap_in_use -= memh->len;
00699         if (munmap(memh, memh->len + sizeof(MemHead) + sizeof(MemTail)))
00700             printf("Couldn't unmap memory %s\n", memh->name);
00701     }
00702     else {
00703         if(malloc_debug_memset && memh->len)
00704             memset(memh+1, 255, memh->len);
00705         free(memh);
00706     }
00707 }
00708 
00709 static void MemorY_ErroR(const char *block, const char *error)
00710 {
00711     print_error("Memoryblock %s: %s\n",block, error);
00712 
00713 #ifdef WITH_ASSERT_ABORT
00714     abort();
00715 #endif
00716 }
00717 
00718 static const char *check_memlist(MemHead *memh)
00719 {
00720     MemHead *forw,*back,*forwok,*backok;
00721     const char *name;
00722 
00723     forw = membase->first;
00724     if (forw) forw = MEMNEXT(forw);
00725     forwok = NULL;
00726     while(forw){
00727         if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
00728         forwok = forw;
00729         if (forw->next) forw = MEMNEXT(forw->next);
00730         else forw = NULL;
00731     }
00732 
00733     back = (MemHead *) membase->last;
00734     if (back) back = MEMNEXT(back);
00735     backok = NULL;
00736     while(back){
00737         if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
00738         backok = back;
00739         if (back->prev) back = MEMNEXT(back->prev);
00740         else back = NULL;
00741     }
00742 
00743     if (forw != back) return ("MORE THAN 1 MEMORYBLOCK CORRUPT");
00744 
00745     if (forw == NULL && back == NULL){
00746         /* geen foute headers gevonden dan maar op zoek naar memblock*/
00747 
00748         forw = membase->first;
00749         if (forw) forw = MEMNEXT(forw);
00750         forwok = NULL;
00751         while(forw){
00752             if (forw == memh) break;
00753             if (forw->tag1 != MEMTAG1 || forw->tag2 != MEMTAG2) break;
00754             forwok = forw;
00755             if (forw->next) forw = MEMNEXT(forw->next);
00756             else forw = NULL;
00757         }
00758         if (forw == NULL) return NULL;
00759 
00760         back = (MemHead *) membase->last;
00761         if (back) back = MEMNEXT(back);
00762         backok = NULL;
00763         while(back){
00764             if (back == memh) break;
00765             if (back->tag1 != MEMTAG1 || back->tag2 != MEMTAG2) break;
00766             backok = back;
00767             if (back->prev) back = MEMNEXT(back->prev);
00768             else back = NULL;
00769         }
00770     }
00771 
00772     if (forwok) name = forwok->nextname;
00773     else name = "No name found";
00774 
00775     if (forw == memh){
00776         /* voor alle zekerheid wordt dit block maar uit de lijst gehaald */
00777         if (forwok){
00778             if (backok){
00779                 forwok->next = (MemHead *)&backok->next;
00780                 backok->prev = (MemHead *)&forwok->next;
00781                 forwok->nextname = backok->name;
00782             } else{
00783                 forwok->next = NULL;
00784                 membase->last = (struct localLink *) &forwok->next;
00785 /*                  membase->last = (struct Link *) &forwok->next; */
00786             }
00787         } else{
00788             if (backok){
00789                 backok->prev = NULL;
00790                 membase->first = &backok->next;
00791             } else{
00792                 membase->first = membase->last = NULL;
00793             }
00794         }
00795     } else{
00796         MemorY_ErroR(name,"Additional error in header");
00797         return("Additional error in header");
00798     }
00799 
00800     return(name);
00801 }
00802 
00803 uintptr_t MEM_get_peak_memory(void)
00804 {
00805     uintptr_t _peak_mem;
00806 
00807     mem_lock_thread();
00808     _peak_mem = peak_mem;
00809     mem_unlock_thread();
00810 
00811     return _peak_mem;
00812 }
00813 
00814 void MEM_reset_peak_memory(void)
00815 {
00816     mem_lock_thread();
00817     peak_mem = 0;
00818     mem_unlock_thread();
00819 }
00820 
00821 uintptr_t MEM_get_memory_in_use(void)
00822 {
00823     uintptr_t _mem_in_use;
00824 
00825     mem_lock_thread();
00826     _mem_in_use= mem_in_use;
00827     mem_unlock_thread();
00828 
00829     return _mem_in_use;
00830 }
00831 
00832 uintptr_t MEM_get_mapped_memory_in_use(void)
00833 {
00834     uintptr_t _mmap_in_use;
00835 
00836     mem_lock_thread();
00837     _mmap_in_use= mmap_in_use;
00838     mem_unlock_thread();
00839 
00840     return _mmap_in_use;
00841 }
00842 
00843 int MEM_get_memory_blocks_in_use(void)
00844 {
00845     int _totblock;
00846 
00847     mem_lock_thread();
00848     _totblock= totblock;
00849     mem_unlock_thread();
00850 
00851     return _totblock;
00852 }
00853 
00854 #ifndef NDEBUG
00855 const char *MEM_name_ptr(void *vmemh)
00856 {
00857     if (vmemh) {
00858         MemHead *memh= vmemh;
00859         memh--;
00860         return memh->name;
00861     }
00862     else {
00863         return "MEM_name_ptr(NULL)";
00864     }
00865 }
00866 #endif
00867 
00868 /* eof */