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