/*
 * Copyright (C) 2001-2003 FhG Fokus
 *
 * This file is part of opensips, a free SIP server.
 *
 * opensips is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * opensips 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */


#if !defined(VQ_MALLOC_H) && defined(VQ_MALLOC)
#define VQ_MALLOC_H

#include "../config.h"
#include "meminfo.h"

/* indicates this fragment is not in use (must not be offset of valid
   aligned fragment beginning
*/
#define	FR_USED		0xef

/*useful macros*/
#define FRAG_END(f)  \
	((struct vqm_frag_end*)((char*)(f)-sizeof(struct vqm_frag_end)+ \
	(f)->size))

#define FRAG_NEXT(f) \
	((struct vqm_frag*)((char*)(f)+(f)->size))

#define PREV_FRAG_END(f) \
	((struct vqm_frag_end*)((char*)(f)-sizeof(struct vqm_frag_end)))

#define FRAG_PREV(f) \
	( (struct vqm_frag*) ( (char*)(f) - PREV_FRAG_END(f)->size ))

#define FRAG_ISUSED(f) \
	((f)->u.inuse.magic==FR_USED)

/* just a bumper for the step function */
#define EO_STEP                         -1


#ifdef DBG_MALLOC
#	define ST_CHECK_PATTERN   	0xf0f0f0f0
#	define END_CHECK_PATTERN  	"sExP"
#	define END_CHECK_PATTERN_LEN 	4
#	define VQM_OVERHEAD (sizeof(struct vqm_frag)+ \
							sizeof(struct vqm_frag_end)+END_CHECK_PATTERN_LEN)
#	define VQM_DEBUG_FRAG(qm, f) vqm_debug_frag( (qm), (f))
#else
#	define VQM_DEBUG_FRAG(qm, f)
#	define VQM_OVERHEAD (sizeof(struct vqm_frag)+ sizeof(struct vqm_frag_end))
#endif



struct vqm_frag {
	/* XXX */
	/* total chunk size including all overhead/bellowfoot/roundings/etc */
	/* useless as otherwise size implied by bucket (if I really want to save
       bytes, I'll remove it  from here */
	unsigned long size;
	union{
		/* pointer to next chunk in a bucket if free */
		struct vqm_frag* nxt_free;
		struct {   /* or bucket number if busy */
			unsigned char magic;
			unsigned char bucket;
        } inuse;
	} u;
#ifdef DBG_MALLOC
	/* source code info */
	char* file;
	char* func;
	unsigned long line;
	/* your safety is important to us! safety signatures */
	unsigned long check;
	char *end_check;
	/* the size user was originally asking for */
	unsigned long demanded_size;
#endif
};

struct vqm_frag_end{
	/* total chunk size including all overhead/bellowfoot/roundings/etc */
	unsigned long size;
	/* XXX */
	/* used only for variable-size chunks; might have different
           data structures for variable/fixed length chunks */
	struct vqm_frag* prv_free;
};


struct vqm_block{
	/* size to bucket table */
	unsigned char s2b[ MAX_FIXED_BLOCK ];
	/* size to rounded size */
	unsigned short s2s[ MAX_FIXED_BLOCK ];
	unsigned char max_small_bucket;

	/* core gained on init ... */
	char *core, *init_core, *core_end;
	/* ... and its available net amount; note that there's lot of
           free memory in buckets too -- this just tells about memory
	   which has not been assigned to chunks  */
	unsigned long free_core;
	/* we allocate huge chunks from the end on; this is the
	   pointer to big chunks
    */
	char *big_chunks;

	struct vqm_frag* next_free[ MAX_BUCKET +1];
#ifdef DBG_MALLOC
	unsigned long usage[ MAX_BUCKET +1];
#endif
};



struct vqm_block* vqm_malloc_init(char* address, unsigned int size);

#ifdef DBG_MALLOC
void vqm_debug_frag(struct vqm_block* qm, struct vqm_frag* f);
void* vqm_malloc(struct vqm_block*, unsigned int size, char* file, char* func,
					unsigned int line);
void  vqm_free(struct vqm_block*, void* p, char* file, char* func,
				unsigned int line);
#else
void* vqm_malloc(struct vqm_block*, unsigned int size);
void  vqm_free(struct vqm_block*, void* p);
#endif

void  vqm_status(struct vqm_block*);


#endif
