diff options
author | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-02-13 09:41:20 +0000 |
---|---|---|
committer | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2008-02-13 09:41:20 +0000 |
commit | 71d75dcb2b25a8df05fdf04eadecca560960fd90 (patch) | |
tree | 6ca20ebb26bfd4e1449b45c90775bd74f7fe9e57 | |
parent | f298f7b24bca05428fcef277acf1e914bb50cb14 (diff) | |
download | hercules-71d75dcb2b25a8df05fdf04eadecca560960fd90.tar.gz hercules-71d75dcb2b25a8df05fdf04eadecca560960fd90.tar.bz2 hercules-71d75dcb2b25a8df05fdf04eadecca560960fd90.tar.xz hercules-71d75dcb2b25a8df05fdf04eadecca560960fd90.zip |
Merged memory manager updates from old jA revisions (bugreport:663)
Produces less memory overhead and has better overflow detection.
Caution, experimental / not fully tested code! (seems to work though...)
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12198 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Trunk.txt | 3 | ||||
-rw-r--r-- | src/common/malloc.c | 530 |
2 files changed, 228 insertions, 305 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 50f836594..6e1e8efa4 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,9 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2008/02/13 + * Merged memory manager updates from old jA revisions (bugreport:663) + - less overhead and better overflow detection (caution, experimental!) 2008/02/11 * 'Forget me Not' no longer blocks ASPD bonuses from working or prevents their re-casting, they are simply dispelled when the effect takes place. diff --git a/src/common/malloc.c b/src/common/malloc.c index 8b985bbd7..88d43b21e 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -129,83 +129,100 @@ char* _bstrdup(const char *chr) * 出来ていたりします。(padding,unit_head を除く) * * ・ブロック同士はリンクリスト(block_prev,block_next) でつながり、同じサイ - * ズを持つブロック同士もリンクリスト(samesize_prev,samesize_nect) でつな + * ズを持つブロック同士もリンクリスト(hash_prev,hash_nect) でつな * がっています。それにより、不要となったメモリの再利用が効率的に行えます。 */ +/* ブロックのアライメント */ +#define BLOCK_ALIGNMENT1 16 +#define BLOCK_ALIGNMENT2 64 + /* ブロックに入るデータ量 */ -#define BLOCK_DATA_SIZE 80*1024 +#define BLOCK_DATA_COUNT1 128 +#define BLOCK_DATA_COUNT2 608 -/* 一度に確保するブロックの数。 */ -#define BLOCK_ALLOC 32 +/* ブロックの大きさ: 16*128 + 64*576 = 40KB */ +#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 ) +#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 ) +#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 ) -/* ブロックのアライメント */ -#define BLOCK_ALIGNMENT 64 +/* 一度に確保するブロックの数。 */ +#define BLOCK_ALLOC 104 /* ブロック */ struct block { - int block_no; /* ブロック番号 */ - struct block* block_prev; /* 前に確保した領域 */ struct block* block_next; /* 次に確保した領域 */ - int samesize_no; /* 同じサイズの番号 */ - struct block* samesize_prev; /* 同じサイズの前の領域 */ - struct block* samesize_next; /* 同じサイズの次の領域 */ - size_t unit_size; /* ユニットのバイト数 0=未使用 */ - size_t unit_hash; /* ユニットのハッシュ */ - int unit_count; /* ユニットの数 */ - int unit_used; /* 使用済みユニット */ - char data[BLOCK_DATA_SIZE]; + struct block* unfill_prev; /* 次の埋まっていない領域 */ + struct block* unfill_next; /* 次の埋まっていない領域 */ + unsigned short unit_size; /* ユニットの大きさ */ + unsigned short unit_hash; /* ユニットのハッシュ */ + unsigned short unit_count; /* ユニットの個数 */ + unsigned short unit_used; /* 使用ユニット数 */ + unsigned short unit_unfill; /* 未使用ユニットの場所 */ + unsigned short unit_maxused; /* 使用ユニットの最大値 */ + char data[ BLOCK_DATA_SIZE ]; }; struct unit_head { - struct block* block; - size_t size; - const char* file; - int line; - unsigned int checksum; -}; - -struct chunk { - char *block; - struct chunk *next; + struct block *block; + const char* file; + unsigned short line; + unsigned short size; + long checksum; }; -static struct block* block_first = NULL; -static struct block* block_last = NULL; -static struct block* block_unused = NULL; - -/* ユニットへのハッシュ。80KB/64Byte = 1280個 */ -static struct block* unit_first[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最初 */ -static struct block* unit_unfill[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 埋まってない */ -static struct block* unit_last[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最後 */ +static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1]; +static struct block* block_first, *block_last, block_head; /* メモリを使い回せない領域用のデータ */ struct unit_head_large { + size_t size; struct unit_head_large* prev; struct unit_head_large* next; struct unit_head unit_head; }; + static struct unit_head_large *unit_head_large_first = NULL; -static struct chunk *chunk_first = NULL; +static struct block* block_malloc(unsigned short hash); +static void block_free(struct block* p); +static size_t memmgr_usage_bytes; -static struct block* block_malloc(void); -static void block_free(struct block* p); -static void memmgr_info(void); -static unsigned int memmgr_usage_bytes = 0; +#define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ])) +#define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0) + +static unsigned short size2hash( size_t size ) +{ + if( size <= BLOCK_DATA_SIZE1 ) { + return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1; + } else if( size <= BLOCK_DATA_SIZE ){ + return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2 + + BLOCK_DATA_COUNT1; + } else { + return 0xffff; // ブロック長を超える場合は hash にしない + } +} + +static size_t hash2size( unsigned short hash ) +{ + if( hash <= BLOCK_DATA_COUNT1) { + return hash * BLOCK_ALIGNMENT1; + } else { + return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1; + } +} void* _mmalloc(size_t size, const char *file, int line, const char *func ) { - int i; struct block *block; - size_t size_hash; + short size_hash = size2hash( size ); + struct unit_head *head; if (((long) size) < 0) { ShowError("_mmalloc: %d\n", size); return 0; } - size_hash = (size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT; if(size == 0) { return NULL; } @@ -213,11 +230,12 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) /* ブロック長を超える領域の確保には、malloc() を用いる */ /* その際、unit_head.block に NULL を代入して区別する */ - if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { + if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); if(p != NULL) { + p->size = size; p->unit_head.block = NULL; - p->unit_head.size = size; + p->unit_head.size = 0; p->unit_head.file = file; p->unit_head.line = line; p->prev = NULL; @@ -228,12 +246,8 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) p->next = unit_head_large_first; } unit_head_large_first = p; -#ifdef DEBUG_MEMMGR - // set allocated data to 0xCD (clean memory) - memset((char *)p + sizeof(struct unit_head_large) - sizeof(int), 0xCD, size); -#endif - *(int*)((char*)p + sizeof(struct unit_head_large) - sizeof(int) + size) = 0xdeadbeaf; - return (char *)p + sizeof(struct unit_head_large) - sizeof(int); + *(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)p + sizeof(struct unit_head_large) - sizeof(long); } else { ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line); exit(EXIT_FAILURE); @@ -241,68 +255,66 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) } /* 同一サイズのブロックが確保されていない時、新たに確保する */ - if(unit_unfill[size_hash] == NULL) { - block = block_malloc(); - if(unit_first[size_hash] == NULL) { - /* 初回確保 */ - unit_first[size_hash] = block; - unit_last[size_hash] = block; - block->samesize_no = 0; - block->samesize_prev = NULL; - block->samesize_next = NULL; + if(hash_unfill[size_hash]) { + block = hash_unfill[size_hash]; + } else { + block = block_malloc(size_hash); + } + + if( block->unit_unfill == 0xFFFF ) { + // free済み領域が残っていない + memmgr_assert(block->unit_used < block->unit_count); + memmgr_assert(block->unit_used == block->unit_maxused); + head = block2unit(block, block->unit_maxused); + block->unit_used++; + block->unit_maxused++; + } else { + head = block2unit(block, block->unit_unfill); + block->unit_unfill = head->size; + block->unit_used++; + } + + if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) { + // ユニットを使い果たしたので、unfillリストから削除 + if( block->unfill_prev == &block_head) { + hash_unfill[ size_hash ] = block->unfill_next; } else { - /* 連結作業 */ - unit_last[size_hash]->samesize_next = block; - block->samesize_no = unit_last[size_hash]->samesize_no + 1; - block->samesize_prev = unit_last[size_hash]; - block->samesize_next = NULL; - unit_last[size_hash] = block; + block->unfill_prev->unfill_next = block->unfill_next; } - unit_unfill[size_hash] = block; - block->unit_size = size_hash * BLOCK_ALIGNMENT + sizeof(struct unit_head); - block->unit_count = (int)(BLOCK_DATA_SIZE / block->unit_size); - block->unit_used = 0; - block->unit_hash = size_hash; - /* 未使用Flagを立てる */ - for(i=0;i<block->unit_count;i++) { - ((struct unit_head*)(&block->data[block->unit_size * i]))->block = NULL; + if( block->unfill_next ) { + block->unfill_next->unfill_prev = block->unfill_prev; } - } - /* ユニット使用個数加算 */ - block = unit_unfill[size_hash]; - block->unit_used++; - - /* ユニット内を全て使い果たした */ - if(block->unit_count == block->unit_used) { - do { - unit_unfill[size_hash] = unit_unfill[size_hash]->samesize_next; - } while( - unit_unfill[size_hash] != NULL && - unit_unfill[size_hash]->unit_count == unit_unfill[size_hash]->unit_used - ); + block->unfill_prev = NULL; } - /* ブロックの中の空きユニット捜索 */ - for(i=0;i<block->unit_count;i++) { - struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]); - if(head->block == NULL) { - head->block = block; - head->size = size; - head->line = line; - head->file = file; #ifdef DEBUG_MEMMGR - // set allocated memory to 0xCD (clean memory) - memset((char *)head + sizeof(struct unit_head) - sizeof(int), 0xCD, size); -#endif - *(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + size) = 0xdeadbeaf; - return (char *)head + sizeof(struct unit_head) - sizeof(int); + { + size_t i, sz = hash2size( size_hash ); + for( i=0; i<sz; i++ ) + { + if( ((unsigned char*)head)[ sizeof(struct unit_head) - sizeof(long) + i] != 0xfd ) + { + if( head->line != 0xfdfd ) + { + ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line); + } + else + { + ShowError("Memory manager: not-allocated-data is changed.\n"); + } + break; + } } + memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz ); } - // ここに来てはいけない。 - ShowFatalError("Memory manager::memmgr_malloc() serious error (allocating %d+%d bytes at %s:%d)\n", sizeof(struct unit_head_large), size, file, line); - memmgr_info(); - exit(EXIT_FAILURE); - //return NULL; +#endif + + head->block = block; + head->file = file; + head->line = line; + head->size = (unsigned short)size; + *(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf; + return (char *)head + sizeof(struct unit_head) - sizeof(long); }; void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) @@ -319,7 +331,10 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c return _mmalloc(size,file,line,func); } - old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(int)))->size; + old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; + if( old_size == 0 ) { + old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size; + } if(old_size > size) { // サイズ縮小 -> そのまま返す(手抜き) return memblock; @@ -349,24 +364,21 @@ char* _mstrdup(const char *p, const char *file, int line, const char *func ) void _mfree(void *ptr, const char *file, int line, const char *func ) { struct unit_head *head; - size_t size_hash; if (ptr == NULL) return; - head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(int)); - size_hash = (head->size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT; - - if(head->block == NULL) { - if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { - /* malloc() で直に確保された領域 */ - struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(int)); - if( - *(int*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(int) + head->size) - != 0xdeadbeaf) - { - ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line); - } + head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long)); + if(head->size == 0) { + /* malloc() で直に確保された領域 */ + struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long)); + if( + *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) + != 0xdeadbeaf) + { + ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line); + } else { + head->size = -1; if(head_large->prev) { head_large->prev->next = head_large->next; } else { @@ -375,192 +387,123 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) if(head_large->next) { head_large->next->prev = head_large->prev; } - head->block = NULL; - memmgr_usage_bytes -= head->size; + memmgr_usage_bytes -= head_large->size; #ifdef DEBUG_MEMMGR - // set freed memory to 0xDD (dead memory) - memset(ptr, 0xDD, head->size); + // set freed memory to 0xfd + memset(ptr, 0xfd, head_large->size); #endif FREE(head_large,file,line,func); - } else { - ShowError("Memory manager: args of aFree is freed pointer %s:%d@%s\n", file, line, func); } - ptr = NULL; - return; } else { /* ユニット解放 */ struct block *block = head->block; - if((unsigned long)block % sizeof(struct block) != 0) { - ShowError("Memory manager: args of aFree is not valid pointer %s line %d\n", file, line); - } else if(*(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + head->size) != 0xdeadbeaf) { + if( (char*)head - (char*)block > sizeof(struct block) ) { + ShowError("Memory manager: args of aFree is invalid pointer %s line %d\n",file,line); + } else if(head->block == NULL) { + ShowError("Memory manager: args of aFree is freed pointer %s:%d@%s\n", file, line, func); + } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line); } else { - head->block = NULL; + memmgr_usage_bytes -= head->size; + head->block = NULL; #ifdef DEBUG_MEMMGR - // set freed memory to 0xDD (dead memory) - memset(ptr, 0xDD, head->size); + memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) ); + head->file = file; + head->line = line; #endif - memmgr_usage_bytes -= head->size; + memmgr_assert( block->unit_used > 0 ); if(--block->unit_used == 0) { /* ブロックの解放 */ - if(unit_unfill[block->unit_hash] == block) { - /* 空きユニットに指定されている */ - do { - unit_unfill[block->unit_hash] = unit_unfill[block->unit_hash]->samesize_next; - } while( - unit_unfill[block->unit_hash] != NULL && - unit_unfill[block->unit_hash]->unit_count == unit_unfill[block->unit_hash]->unit_used - ); - } - if(block->samesize_prev == NULL && block->samesize_next == NULL) { - /* 独立ブロックの解放 */ - unit_first[block->unit_hash] = NULL; - unit_last[block->unit_hash] = NULL; - unit_unfill[block->unit_hash] = NULL; - } else if(block->samesize_prev == NULL) { - /* 先頭ブロックの解放 */ - unit_first[block->unit_hash] = block->samesize_next; - (block->samesize_next)->samesize_prev = NULL; - } else if(block->samesize_next == NULL) { - /* 末端ブロックの解放 */ - unit_last[block->unit_hash] = block->samesize_prev; - (block->samesize_prev)->samesize_next = NULL; - } else { - /* 中間ブロックの解放 */ - (block->samesize_next)->samesize_prev = block->samesize_prev; - (block->samesize_prev)->samesize_next = block->samesize_next; - } block_free(block); } else { - /* 空きユニットの再設定 */ - if( - unit_unfill[block->unit_hash] == NULL || - unit_unfill[block->unit_hash]->samesize_no > block->samesize_no - ) { - unit_unfill[block->unit_hash] = block; + if( block->unfill_prev == NULL) { + // unfill リストに追加 + if( hash_unfill[ block->unit_hash ] ) { + hash_unfill[ block->unit_hash ]->unfill_prev = block; + } + block->unfill_prev = &block_head; + block->unfill_next = hash_unfill[ block->unit_hash ]; + hash_unfill[ block->unit_hash ] = block; } + head->size = block->unit_unfill; + block->unit_unfill = (unsigned short)(((unsigned long)head - (unsigned long)block->data) / block->unit_size); } - ptr = NULL; } } } -/* 現在の状況を表示する */ -static void memmgr_info(void) +/* ブロックを確保する */ +static struct block* block_malloc(unsigned short hash) { int i; struct block *p; - ShowInfo("** Memory Manager Information **\n"); - if(block_first == NULL) { - ShowMessage("Uninitialized.\n"); - return; - } - ShowMessage( - "Blocks: %04u , BlockSize: %06u Byte , Used: %08uKB\n", - block_last->block_no+1,sizeof(struct block), - (block_last->block_no+1) * sizeof(struct block) / 1024 - ); - p = block_first; - for(i=0;i<=block_last->block_no;i++) { - ShowMessage(" Block #%04u : ",p->block_no); - if(p->unit_size == 0) { - ShowMessage("unused.\n"); - } else { - ShowMessage( - "size: %05u byte. used: %04u/%04u prev:", - p->unit_size - sizeof(struct unit_head),p->unit_used,p->unit_count - ); - if(p->samesize_prev == NULL) { - ShowMessage("NULL"); - } else { - ShowMessage("%04u",(p->samesize_prev)->block_no); - } - ShowMessage(" next:"); - if(p->samesize_next == NULL) { - ShowMessage("NULL"); - } else { - ShowMessage("%04u",(p->samesize_next)->block_no); - } - ShowMessage("\n"); - } - p = p->block_next; - } -} - -/* ブロックを確保する */ -static struct block* block_malloc(void) -{ - if(block_unused != NULL) { + if(hash_unfill[0] != NULL) { /* ブロック用の領域は確保済み */ - struct block* ret = block_unused; - do { - block_unused = block_unused->block_next; - } while(block_unused != NULL && block_unused->unit_size != 0); - return ret; + p = hash_unfill[0]; + hash_unfill[0] = hash_unfill[0]->unfill_next; } else { /* ブロック用の領域を新たに確保する */ - int i; - int block_no; - struct block* p; - struct chunk* chunk; - char *pb = (char *)CALLOC(sizeof(struct block),BLOCK_ALLOC+1,file,line,func); - if(pb == NULL) { + p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), file,line,func ); + if(p == NULL) { ShowFatalError("Memory manager::block_alloc failed.\n"); exit(EXIT_FAILURE); } - // store original block address in chunk - chunk = (struct chunk *)MALLOC(sizeof(struct chunk),file,line,func); - if (chunk == NULL) { - ShowFatalError("Memory manager::block_alloc failed.\n"); - exit(EXIT_FAILURE); - } - chunk->block = pb; - chunk->next = (chunk_first) ? chunk_first : NULL; - chunk_first = chunk; - - // ブロックのポインタの先頭をsizeof(block) アライメントに揃える - // このアドレスをfree() することはないので、直接ポインタを変更している。 - pb += sizeof(struct block) - ((unsigned long)pb % sizeof(struct block)); - p = (struct block*)pb; if(block_first == NULL) { /* 初回確保 */ - block_no = 0; - block_first = p; + block_first = p; } else { - block_no = block_last->block_no + 1; block_last->block_next = p; - p->block_prev = block_last; } block_last = &p[BLOCK_ALLOC - 1]; + block_last->block_next = NULL; /* ブロックを連結させる */ for(i=0;i<BLOCK_ALLOC;i++) { if(i != 0) { - p[i].block_prev = &p[i-1]; + // p[0] はこれから使うのでリンクには加えない + p[i].unfill_next = hash_unfill[0]; + hash_unfill[0] = &p[i]; + p[i].unfill_prev = NULL; } if(i != BLOCK_ALLOC -1) { p[i].block_next = &p[i+1]; } - p[i].block_no = block_no + i; } - - /* 未使用ブロックへのポインタを更新 */ - block_unused = &p[1]; - p->unit_size = 1; - return p; } + + // unfill に追加 + memmgr_assert(hash_unfill[ hash ] == NULL); + hash_unfill[ hash ] = p; + p->unfill_prev = &block_head; + p->unfill_next = NULL; + p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head)); + p->unit_hash = hash; + p->unit_count = BLOCK_DATA_SIZE / p->unit_size; + p->unit_used = 0; + p->unit_unfill = 0xFFFF; + p->unit_maxused = 0; +#ifdef DEBUG_MEMMGR + memset( p->data, 0xfd, sizeof(p->data) ); +#endif + return p; } static void block_free(struct block* p) { - /* free() せずに、未使用フラグを付けるだけ */ - p->unit_size = 0; - /* 未使用ポインターを更新する */ - if(block_unused == NULL) { - block_unused = p; - } else if(block_unused->block_no > p->block_no) { - block_unused = p; + if( p->unfill_prev ) { + if( p->unfill_prev == &block_head) { + hash_unfill[ p->unit_hash ] = p->unfill_next; + } else { + p->unfill_prev->unfill_next = p->unfill_next; + } + if( p->unfill_next ) { + p->unfill_next->unfill_prev = p->unfill_prev; + } + p->unfill_prev = NULL; } + + p->unfill_next = hash_unfill[0]; + hash_unfill[0] = p; } unsigned int memmgr_usage (void) @@ -592,75 +535,43 @@ static void memmgr_log (char *buf) static void memmgr_final (void) { struct block *block = block_first; - struct chunk *chunk = chunk_first, *chunk2; - struct unit_head_large *large = unit_head_large_first, *large2; - int i; + struct unit_head_large *large = unit_head_large_first; #ifdef LOG_MEMMGR int count = 0; - char buf[128]; #endif while (block) { - if (block->unit_size) { - for (i = 0; i < block->unit_count; i++) { - struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]); - if(head->block != NULL) - { - #ifdef LOG_MEMMGR + if (block->unfill_prev) { + int i; + for (i = 0; i < block->unit_maxused; i++) { + struct unit_head *head = block2unit(block, i); + if(head->block != NULL) { +#ifdef LOG_MEMMGR + char buf[128]; sprintf (buf, "%04d : %s line %d size %lu\n", ++count, head->file, head->line, (unsigned long)head->size); memmgr_log (buf); - #endif +#endif // get block pointer and free it [celest] - _mfree ((char *)head + sizeof(struct unit_head) - sizeof(int), ALC_MARK); + _mfree ((char *)head + sizeof(struct unit_head) - sizeof(short), ALC_MARK); } } } - //if (block->block_no >= block2->block_no + BLOCK_ALLOC - 1) { - // reached a new block array - //block = block->block_next; - - /* Okay wise guys... this is how block2 was allocated: [Skotlex] - struct block* p; - char *pb = (char *) CALLOC (sizeof(struct block),BLOCK_ALLOC + 1); - pb += sizeof(struct block) - ((unsigned long)pb % sizeof(struct block)); - p = (struct block*)pb; - - The reason we get an invalid pointer is that we allocated pb, not p. - So how do you get pb when you only have p? - The answer is, you can't, because the original pointer was lost when - memory-aligning the block. So we either forget this FREE or use a - self-reference... - Since we are already quitting, it might be ok to just not free the block - as it is. - */ - // didn't realise that before o.o -- block chunks are now freed below [celest] - // FREE(block2); - //block2 = block; - //continue; - //} block = block->block_next; } - // free the allocated block chunks - chunk = chunk_first; - while (chunk) { - chunk2 = chunk->next; - FREE(chunk->block,file,line,func); - FREE(chunk,file,line,func); - chunk = chunk2; - } - while(large) { - large2 = large->next; - #ifdef LOG_MEMMGR + struct unit_head_large *large2; +#ifdef LOG_MEMMGR + char buf[128]; sprintf (buf, "%04d : %s line %d size %lu\n", ++count, large->unit_head.file, large->unit_head.line, (unsigned long)large->unit_head.size); memmgr_log (buf); - #endif +#endif + large2 = large->next; FREE(large,file,line,func); large = large2; } @@ -677,10 +588,10 @@ static void memmgr_final (void) static void memmgr_init (void) { - #ifdef LOG_MEMMGR - sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); - ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); - #endif +#ifdef LOG_MEMMGR + sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); + ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); +#endif return; } #endif @@ -691,6 +602,15 @@ static void memmgr_init (void) *-------------------------------------- */ +bool malloc_verify(void* ptr) +{ +#ifdef USE_MEMMGR + +#endif + + return true; +} + unsigned int malloc_usage (void) { #ifdef USE_MEMMGR |