summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-02-13 09:41:20 +0000
committerultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2008-02-13 09:41:20 +0000
commit71d75dcb2b25a8df05fdf04eadecca560960fd90 (patch)
tree6ca20ebb26bfd4e1449b45c90775bd74f7fe9e57
parentf298f7b24bca05428fcef277acf1e914bb50cb14 (diff)
downloadhercules-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.txt3
-rw-r--r--src/common/malloc.c530
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