/**********************************************************************
 
	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.

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


#ifndef ___MEMORY_ROUTINE_H___
#define ___MEMORY_ROUTINE_H___

#define GC_THREAD_HASH_SIZE	100
#define GC_LIST_HASH_SIZE	23


typedef struct mem {
	struct mem *	m_next;
	struct mem *	m_prev;
	long		m_flags;
#define M_GC		((long)0x80000000)
#define M_STACK		((long)0x40000000)
	long		m_size;
} MEM;


#define MEM2PT(m)	((void*)((m)+1))
#define PT2MEM(pt)	(((MEM*)(pt))-1)


#define _TEST_AND_RESET(m)	\
	(					\
		((m)->m_flags &			\
			(M_GC)) ?		\
		(((m)->m_flags &= ~M_GC) , 1) :	\
		0				\
	)
#define _TEST_AND_SET(m)	\
	(							\
		((m)->m_flags & (M_GC)) ?			\
			1 :					\
			(((m)->m_flags |= M_GC) , 0)		\
	)

#define TEST_AND_RESET(m)	_TEST_AND_RESET(PT2MEM(m))
#define TEST_AND_SET(m)		_TEST_AND_SET(PT2MEM(m))
#define TEST_MEM(m)		(PT2MEM(m)->m_flags)

#define GC_HEADER	\
	if ( p == 0 )		\
		return;		\
	if ( TEST_AND_SET(p) )	\
		return;


typedef struct gc_list {
	struct gc_list *	next;
	void *			mem;
	void			(*gc)();
} GC_LIST;

typedef struct gc_stack {
	struct gc_stack *	parent;
	struct gc_list *	hash[GC_LIST_HASH_SIZE];
	char *			msg;
} GC_STACK;

typedef struct gc_thread {
	struct gc_thread *	next;
	int			tid;
	GC_STACK *		stack;
} GC_THREAD;


void * mmalloc(unsigned long,void (*)());
void * mrealloc(void*,unsigned long,void (*)());
int mem_gc();
void gc_text(char*);

void gc_set_ptr(void * ptr,int (*gc_func)());
void gc_reset_ptr();
void gc_enable();
void gc_disenable();
void gc_permit();
void gc_permit_exit();

char * copy_mstr(char *);

void * min_malloc(int);
void * min_realloc(void*,int);
void min_free(void*);

GC_THREAD * _search_me(int * tidp,int * keyp);
GC_THREAD * _get_gc_my_thread();
GC_THREAD * get_gc_my_thread();
void _push_stack(GC_THREAD * t,char *msg);
void _pop_stack(GC_THREAD * t);
void _insert_gc_list(GC_STACK * st,void * s,void (*gc)());
int _delete_gc_list(GC_STACK * st,void * s);
void _gc_set(GC_THREAD * t,void * s,void (*gc)());
void gc_set(void * s,void (*gc)());
void gc_set_nl(void * s,void (*gc)());
void _gc_delete(GC_THREAD * t,void * s);
void _gc_push(GC_THREAD * t,void * s,void (*gc)(),char *);
void _gc_pop(GC_THREAD * t,void * s,void (*gc)());
void gc_push(void * s,void (*gc)(),char *);
void gc_pop(void * s,void (*gc)());
void gc_delete(void * s);
void gc_delete_nl(void * s);
void resize_gc_mem_nl(void * old,void * new);

#endif
