/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/

/********************************************

	memory manage and gc routine
	(c) H.Mori 1992.9.
	memory_routine.c


*********************************************/

#include "memory_debug.h"

#include <stdlib.h>
#include <stdio.h>
#include	"lock_level.h"
#include	"task.h"
#include "memory_debug.h"
#include "memory_routine.h"

void mem_test(char * msg);

#define GC_THRE  2000000
int GC_RESET = 50;
int GC_LOW   = 50;


SEM mem_lock;

#define INSERT_MEM(n,e)		\
	(e)->m_prev = (n);		\
	(e)->m_next = (n)->m_next;	\
	(n)->m_next = (e);		\
	(e)->m_next->m_prev = (e);
#define DELETE_MEM(e)	\
	(e)->m_prev->m_next = (e)->m_next;	\
	(e)->m_next->m_prev = (e)->m_prev;
#define INIT_MEM(n)	\
	(n)->m_next = (n)->m_prev = (n);

#define SIZEOF_MEM	sizeof(MEM)


void * dumy_mem;
int malloc_count;
int malloc_max = GC_THRE;
int abs_malloc;

MEM mem_header;
int mem_tid,mem_cnt;



void
minit()
{
	mem_lock = new_lock(LL_MEMORY);
	INIT_MEM(&mem_header);
	mem_header.m_flags = 0;
}


void
lock_mem()
{
int tid;
	tid = get_tid();
	if ( mem_tid == tid ) {
		mem_cnt ++;
		return;
	}
	lock_task(mem_lock);
	mem_tid = tid;
	mem_cnt = 1;
}

void
unlock_mem()
{
	if ( mem_tid != get_tid() )
		er_panic("unlock_mem");
	mem_cnt --;
	if ( mem_cnt == 0 ) {
		mem_tid = 0;
		unlock_task(mem_lock,"unlock_mem");
	}
}

void
_mem_debug1()
{
void * a;
	a = malloc(56);
	free(a);
}

void *
mmalloc(unsigned long size,void (*gc_func)())
{
void * ret;
int i;
char * pt;
MEM * m;

	if ( dumy_mem == 0 ) {
		dumy_mem = malloc(1000);
		if ( dumy_mem == 0 )
			er_panic("no memory!!");
	}
	if ( (m = malloc(size+SIZEOF_MEM)) == 0 ) {
		free(dumy_mem);
		er_panic("no memory!!");
	}
	m->m_size = size;
	m->m_flags = 0;
	ret = MEM2PT(m);
	pt = ret;
	for ( i = 0 ; i < size ; i ++ )
		*pt++ = 0;
	lock_mem();
	INSERT_MEM(&mem_header,m);
	malloc_count += size;
	gc_set_nl_non_check(ret,gc_func);
	unlock_mem();

	return ret;
}


void
mfree(void * f)
{
MEM * m;
	lock_mem(); 
	m = PT2MEM(f);
	malloc_count -= m->m_size;
	DELETE_MEM(m);
	gc_delete_nl(f);
	unlock_mem();
	free(m);
}

void *
mrealloc(void * pt,unsigned long size,void (*gc_func)())
{
void * ret;
MEM * m, * new;
int i,s;
char * src, * dest;

	lock_mem();
	if ( pt == 0 )
		er_panic("mrealloc(1)");
	m = PT2MEM(pt);
	if ( m->m_size == size ) {
		unlock_mem();
		return pt;
	}
	new = malloc(size + SIZEOF_MEM);
	if ( new == 0 )
		er_panic("no memmory");
	new->m_size = size;
	new->m_flags = 0;
	ret = MEM2PT(new);
	if ( m->m_size < size )
		s = m->m_size;
	else 	s = size;
	src = pt;
	dest = ret;
	for ( i = 0 ; i < s ; i ++ )
		*dest ++ = *src ++;
	for ( ; i < size ; i ++ )
		*dest ++ = 0;
	m->m_flags |= M_STACK;
	INSERT_MEM(&mem_header,new);
	malloc_count += size;
	gc_set_nl_non_check(ret,gc_func);
	unlock_mem();
	return ret;
}


extern void *test_ptr;

int
_mem_gc()
{
MEM * m,* m1;
int i;
int size;
int ret;
	ret = 0;
	for ( m = mem_header.m_next ; m != &mem_header ; ) {
		if ( m->m_flags ) {
			m->m_flags = 0;
			m = m->m_next;
			continue;
		}
		m1 = m;
		m = m->m_next;
		DELETE_MEM(m1);
		size = m1->m_size;
		for ( i = 0 ; i < size+sizeof(MEM) ; i ++ )
			((char*)m1)[i] = 0x79;
		free(m1);
		ret += size;
	}
	malloc_count = malloc_count-ret;
	return ret;
}

int
mem_gc()
{
int ret;
	lock_mem();
	ret = _mem_gc();
	unlock_mem();
	return ret;
}

char *
copy_mstr(char * str)
{
char * ret;
	ret = mmalloc(strlen(str)+1,gc_text);
	strcpy(ret,str);
	return ret;
}

void
gc_text(char* tx)
{
	if ( tx == 0 )
		return;
	if ( TEST_AND_SET(tx) )
		return;
}

#define TEST_CNT	2000

void
mem_test(char * msg)
{
int i,j;
char ** t;

	printf("%s...",msg);
	fflush(stdout);

	t = d_alloc(sizeof(char*)*TEST_CNT,23);
	for ( i = 0 ; i < TEST_CNT ; i ++ ) {
		t[i] = d_alloc(i+1,24);
		for ( j = 0 ; j < i+1 ; j ++ )
			t[i][j] = 0x77;
	}
	for ( i = 0 ; i < TEST_CNT ; i ++ )
		d_f_ree(t[i]);
	d_f_ree(t);

	printf("END\n");

}

