summaryrefslogblamecommitdiff
path: root/src/common/malloc.c
blob: b81c25ed5c1d3bfbb0a6adf579eacd6839c7fcc3 (plain) (tree)
1
2
3
4
5
6
7
8
9

                   
                   

                   



                     
                                                                     
                    
 
                                                                                       
 


                                                                           
 
                                                                     


                                     
                         
      









                                                                                          
 
                                                                            


                                         
                             
      










                                                                                          
 
                                                                           


                                        
                            
      






                                                                                           
 
                                                                             
 
                  




                                                                     
                                















                                                                                          
      
 
 
                       






                                           
                                          
                                        


                                   


                                  
                                            


                         








































































































































































































                                                                                                                               

                                                                              

                            



                                                                         


















































































































































































































                                                                                                                                     
                           

         
      

                                      




                                                                   

                 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "malloc.h"

#ifdef MEMWATCH
#include "memwatch.h"
#endif

// �Ǝ��������}�l�[�W�����g�p����ꍇ�A���̃R�����g���O���Ă��������B
//#define USE_MEMMGR

#if !defined(DMALLOC) && !defined(GCOLLECT) && !defined(BCHECK) && !defined(USE_MEMMGR)

void* aMalloc_( size_t size, const char *file, int line, const char *func )
{
	void *ret;

//	printf("%s:%d: in func %s: malloc %d\n",file,line,func,size);
#ifdef MEMWATCH
	ret=mwMalloc(size,file,line);
#else
	ret=malloc(size);
#endif
	if(ret==NULL){
		printf("%s:%d: in func %s: malloc error out of memory!\n",file,line,func);
		exit(1);

	}
	return ret;
}
void* aCalloc_( size_t num, size_t size, const char *file, int line, const char *func )
{
	void *ret;

//	printf("%s:%d: in func %s: calloc %d %d\n",file,line,func,num,size);
#ifdef MEMWATCH
	ret=mwCalloc(num,size,file,line);
#else
	ret=calloc(num,size);
#endif
	if(ret==NULL){
		printf("%s:%d: in func %s: calloc error out of memory!\n",file,line,func);
		exit(1);

	}
	return ret;
}

void* aRealloc_( void *p, size_t size, const char *file, int line, const char *func )
{
	void *ret;

//	printf("%s:%d: in func %s: realloc %p %d\n",file,line,func,p,size);
#ifdef MEMWATCH
	ret=mwRealloc(p,size,file,line);
#else
	ret=realloc(p,size);
#endif
	if(ret==NULL){
		printf("%s:%d: in func %s: realloc error out of memory!\n",file,line,func);
		exit(1);

	}
	return ret;
}

char* aStrdup_( const void *p, const char *file, int line, const char *func )
{
	char *ret;
	
	// printf("%s:%d: in func %s: strdup %p\n",file,line,func,p);
#ifdef MEMWATCH
	ret=mwStrdup(p,file,line);
#else
	ret= strdup((char *) p);
#endif
	if(ret==NULL){
		printf("%s:%d: in func %s: strdup error out of memory!\n",file,line,func);
		exit(1);

	}
	return ret;
}

void aFree_( void *p, const char *file, int line, const char *func )
{
	// printf("%s:%d: in func %s: free %p\n",file,line,func,p);
#ifdef MEMWATCH
	mwFree(p,file,line);
#else
	free(p);
#endif
}

#elif defined(GCOLLECT)

void * _bcallocA(size_t size, size_t cnt) {
	void *ret = aMallocA(size * cnt);
	memset(ret, 0, size * cnt);
	return ret;
}

void * _bcalloc(size_t size, size_t cnt) {
	void *ret = aMalloc(size * cnt);
	memset(ret, 0, size * cnt);
	return ret;
}

char * _bstrdup(const char *chr) {
	int len = strlen(chr);
	char *ret = (char*)aMalloc(len + 1);
	strcpy(ret, chr);
	return ret;
}

#elif defined(USE_MEMMGR)

/* USE_MEMMGR */

/*
 * �������}�l�[�W��
 *     malloc , free �̏����������I�ɏo����悤�ɂ������́B
 *     ���G�ȏ������s���Ă���̂ŁA�኱�d���Ȃ邩������܂���B
 *
 * �f�[�^�\���Ȃǁi��������ł����܂���^^; �j
 *     �E�������𕡐��́u�u���b�N�v�ɕ����āA����Ƀu���b�N�𕡐��́u���j�b�g�v
 *       �ɕ����Ă��܂��B���j�b�g�̃T�C�Y�́A�P�u���b�N�̗e�ʂ𕡐��‚ɋϓ��z��
 *       �������̂ł��B���Ƃ��΁A�P���j�b�g32KB�̏ꍇ�A�u���b�N�P�‚�32Byte�̃�
 *       �j�b�g���A1024�W�܂��ďo���Ă�����A64Byte�̃��j�b�g�� 512�W�܂���
 *       �o���Ă����肵�܂��B�ipadding,unit_head �������j
 *
 *     �E���j�b�g���m�̓����N���X�g(block_prev,block_next) �ł‚Ȃ���A�����T�C
 *       �Y�����ƒ��j�b�g���m�������N���X�g(samesize_prev,samesize_nect) �ł‚�
 *       �����Ă��܂��B����ɂ��A�s�v�ƂȂ����������̍ė��p�������I�ɍs���܂��B
 */

/* �u���b�N�ɓ���f�[�^�� */
#define BLOCK_DATA_SIZE	80*1024

/* ��x�Ɋm�ۂ���u���b�N�̐��B */
#define BLOCK_ALLOC		32

/* �u���b�N�̃A���C�����g */
#define BLOCK_ALIGNMENT	64

/* �u���b�N */
struct block {
	int    block_no;		/* �u���b�N�ԍ� */
	struct block* block_prev;		/* �O�Ɋm�ۂ����̈� */
	struct block* block_next;		/* ���Ɋm�ۂ����̈� */
	int    samesize_no;     /* �����T�C�Y�̔ԍ� */
	struct block* samesize_prev;	/* �����T�C�Y�̑O�̗̈� */
	struct block* samesize_next;	/* �����T�C�Y�̎��̗̈� */
	int    unit_size;		/* ���j�b�g�̃o�C�g�� 0=���g�p */
	int    unit_hash;		/* ���j�b�g�̃n�b�V�� */
	int    unit_count;		/* ���j�b�g�̐� */
	int    unit_used;		/* �g�p�ς݃��j�b�g */
	char   data[BLOCK_DATA_SIZE];
};

struct unit_head {
	struct block* block;
	int    size;
	const  char* file;
	int    line;
};

static struct block* block_first  = NULL;
static struct block* block_last   = NULL;
static struct block* block_unused = NULL;

/* ���j�b�g�ւ̃n�b�V���B80KB/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];		/* �Ō� */

/* ���������g���񂹂Ȃ��̈�p�̃f�[�^ */
struct unit_head_large {
	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 block* block_malloc(void);
static void   block_free(struct block* p);
static void memmgr_info(void);

void* aMalloc_(size_t size, const char *file, int line, const char *func ) {
	int i;
	struct block *block;
	int size_hash = (size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
	size = size_hash * BLOCK_ALIGNMENT; /* �A���C�����g�̔{���ɐ؂�グ */

	if(size == 0) {
		return NULL;
	}

	/* �u���b�N���𒴂���̈�̊m�ۂɂ́Amalloc() ��p���� */
	/* ���̍ہAunit_head.block �� NULL �������ċ�ʂ��� */
	if(size > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
#ifdef MEMWATCH
		struct unit_head_large* p = (struct unit_head_large*)mwMalloc(sizeof(struct unit_head_large) + size,file,line);
#else
		struct unit_head_large* p = (struct unit_head_large*)malloc(sizeof(struct unit_head_large) + size);
#endif
		if(p != NULL) {
			p->unit_head.block = NULL;
			p->unit_head.size  = size;
			p->unit_head.file  = file;
			p->unit_head.line  = line;
			if(unit_head_large_first == NULL) {
				unit_head_large_first = p;
				p->next = NULL;
				p->prev = NULL;
			} else {
				unit_head_large_first->prev = p;
				p->prev = NULL;
				p->next = unit_head_large_first;
				unit_head_large_first = p;
			}
			return (char *)p + sizeof(struct unit_head_large);
		} else {
			printf("MEMMGR::memmgr_alloc failed.\n");
			exit(1);
		}
	}

	/* ����T�C�Y�̃u���b�N���m�ۂ���Ă��Ȃ����A�V���Ɋm�ۂ��� */
	if(unit_unfill[size_hash] == NULL) {
		block = block_malloc();
		if(unit_first[size_hash] == NULL) {
			/* ����m�� */
			unit_first[size_hash] = block;
			unit_last[size_hash] = block;
			block->samesize_no = 0;
			block->samesize_prev = NULL;
			block->samesize_next = NULL;
		} else {
			/* �A����� */
			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;
		}
		unit_unfill[size_hash] = block;
		block->unit_size  = size + sizeof(struct unit_head);
		block->unit_count = BLOCK_DATA_SIZE / block->unit_size;
		block->unit_used  = 0;
		block->unit_hash  = size_hash;
		/* ���g�pFlag�𗧂Ă� */
		for(i=0;i<block->unit_count;i++) {
			((struct unit_head*)(&block->data[block->unit_size * i]))->block = NULL;
		}
	}
	/* ���j�b�g�g�p�����Z */
	block = unit_unfill[size_hash];
	block->unit_used++;

	/* ���j�b�g����S�Ďg���ʂ����� */
	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
		);
	}

	/* �u���b�N�̒��̋󂫃��j�b�g�{�� */
	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;
			return (char *)head + sizeof(struct unit_head);
		}
	}
	// �����ɗ��Ă͂����Ȃ��B
	printf("MEMMGR::memmgr_malloc() serious error.\n");
	memmgr_info();
	exit(1);
	return NULL;
};

void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func ) {
	void *p = aMalloc_(num * size,file,line,func);
	memset(p,0,num * size);
	return p;
}

void* aRealloc_(void *memblock, size_t size, const char *file, int line, const char *func ) {
	size_t old_size;
	if(memblock == NULL) {
		return aMalloc_(size,file,line,func);
	}

	old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head)))->size;
	if(old_size > size) {
		// �T�C�Y�k�� -> ���̂܂ܕԂ��i�蔲���j
		return memblock;
	}  else {
		// �T�C�Y�g��
		void *p = aMalloc_(size,file,line,func);
		if(p != NULL) {
			memcpy(p,memblock,old_size);
		}
		aFree_(memblock,file,line,func);
		return p;
	}
}

char* aStrdup_(const void *p, const char *file, int line, const char *func ) {
	if(p == NULL) {
		return NULL;
	} else {
		int  len = strlen(p);
		char *string  = (char *)aMalloc_(len + 1,file,line,func);
		memcpy(string,p,len+1);
		return string;
	}
}

void aFree_(void *ptr, const char *file, int line, const char *func ) {
	struct unit_head *head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head));
	if(ptr == NULL) {
		return;
	} else if(head->block == NULL && head->size > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
		/* malloc() �Œ��Ɋm�ۂ��ꂽ�̈� */
		struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large));
		if(head_large->prev) {
			head_large->prev->next = head_large->next;
		} else {
			unit_head_large_first  = head_large->next;
		}
		if(head_large->next) {
			head_large->next->prev = head_large->prev;
		}
		free(head_large);
		return;
	} else {
		/* ���j�b�g��� */
		struct block *block = head->block;
		if(head->block == NULL) {
			printf("memmgr: args of aFree is freed pointer %s line %d\n",file,line);
		} else {
			head->block = NULL;
			if(--block->unit_used == 0) {
				/* �u���b�N�̉�� */
				if(unit_unfill[block->unit_hash] == block) {
					/* �󂫃��j�b�g�Ɏw�肳��Ă��� */
					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) {
					/* �Ɨ��u���b�N�̉�� */
					unit_first[block->unit_hash]  = NULL;
					unit_last[block->unit_hash]   = NULL;
					unit_unfill[block->unit_hash] = NULL;
				} else if(block->samesize_prev == NULL) {
					/* �擪�u���b�N�̉�� */
					unit_first[block->unit_hash] = block->samesize_next;
					(block->samesize_next)->samesize_prev = NULL;
				} else if(block->samesize_next == NULL) {
					/* ���[�u���b�N�̉�� */
					unit_last[block->unit_hash] = block->samesize_prev; 
					(block->samesize_prev)->samesize_next = NULL;
				} else {
					/* ���ԃu���b�N�̉�� */
					(block->samesize_next)->samesize_prev = block->samesize_prev;
					(block->samesize_prev)->samesize_next = block->samesize_next;
				}
				block_free(block);
			} else {
				/* �󂫃��j�b�g�̍Đݒ� */
				if(
					unit_unfill[block->unit_hash] == NULL ||
					unit_unfill[block->unit_hash]->samesize_no > block->samesize_no
				) {
					unit_unfill[block->unit_hash] = block;
				}
			}
		}
	}
}

/* ���݂̏󋵂�\������ */
static void memmgr_info(void) {
	int i;
	struct block *p;
	printf("** Memory Maneger Information **\n");
	if(block_first == NULL) {
		printf("Uninitialized.\n");
		return;
	}
	printf(
		"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++) {
		printf("    Block #%04u : ",p->block_no);
		if(p->unit_size == 0) {
			printf("unused.\n");
		} else {
			printf(
				"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) {
				printf("NULL");
			} else {
				printf("%04u",(p->samesize_prev)->block_no);
			}
			printf(" next:");
			if(p->samesize_next == NULL) {
				printf("NULL");
			} else {
				printf("%04u",(p->samesize_next)->block_no);
			}
			printf("\n");
		}
		p = p->block_next;
	}
}

/* �u���b�N���m�ۂ��� */
static struct block* block_malloc(void) {
	if(block_unused != NULL) {
		/* �u���b�N�p�̗̈�͊m�ۍς� */
		struct block* ret = block_unused;
		do {
			block_unused = block_unused->block_next;
		} while(block_unused != NULL && block_unused->unit_size != 0);
		return ret;
	} else {
		/* �u���b�N�p�̗̈��V���Ɋm�ۂ��� */
		int i;
		int  block_no;
		struct block* p = (struct block *)calloc(sizeof(struct block),BLOCK_ALLOC);
		if(p == NULL) {
			printf("MEMMGR::block_alloc failed.\n");
			exit(1);
		}
		if(block_first == NULL) {
			/* ����m�� */
			block_no     = 0;
			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];
		/* �u���b�N��A�������� */
		for(i=0;i<BLOCK_ALLOC;i++) {
			if(i != 0) {
				p[i].block_prev = &p[i-1];
			}
			if(i != BLOCK_ALLOC -1) {
				p[i].block_next = &p[i+1];
			}
			p[i].block_no = block_no + i;
		}

		/* ���g�p�u���b�N�ւ̃|�C���^���X�V */
		block_unused = &p[1];
		p->unit_size = 1;
		return p;
	}
}

static void block_free(struct block* p) {
	/* free() �����ɁA���g�p�t���O��t���邾�� */
	p->unit_size = 0;
	/* ���g�p�|�C���^�[���X�V���� */
	if(block_unused == NULL) {
		block_unused = p;
	} else if(block_unused->block_no > p->block_no) {
		block_unused = p;
	}
}

static char memmer_logfile[128];

static FILE* memmgr_log(void) {
	FILE *fp = fopen(memmer_logfile,"w");
	if(!fp) { fp = stdout; }
	fprintf(fp,"memmgr: memory leaks found\n");
	return fp;
}

static void memmer_exit(void) {
	FILE *fp = NULL;
	int i;
	int count = 0;
	struct block *block = block_first;
	struct unit_head_large *large = unit_head_large_first;
	while(block) {
		if(block->unit_size) {
			if(!fp) { fp = memmgr_log(); }
			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) {
					fprintf(
						fp,"%04d : %s line %d size %d\n",++count,
						head->file,head->line,head->size
					);
				}
			}
		}
		block = block->block_next;
	}
	while(large) {
		if(!fp) { fp = memmgr_log(); }
		fprintf(
			fp,"%04d : %s line %d size %d\n",++count,
			large->unit_head.file,
			large->unit_head.line,large->unit_head.size
		);
		large = large->next;
	}
	if(!fp) {
		printf("memmgr: no memory leaks found.\n");
	} else {
		printf("memmgr: memory leaks found.\n");
		fclose(fp);
	}
}
#endif

int do_init_memmgr(const char* file) {
	#ifdef USE_MEMMGR
		sprintf(memmer_logfile,"%s.log",file);
		atexit(memmer_exit);
		printf("memmgr: initialised: %s\n",memmer_logfile);
	#endif
	return 0;
}