/****************************************************************
 *								*
 *	Copyright 2003, 2010 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#ifndef GTM_MALLOC_H__included
#define GTM_MALLOC_H__included

#define GTM_MEMORY_RESERVE_DEFAULT 64	/* 64K reserve "backpocket-cache" released on out-of-memory error */

typedef GTM64_ONLY(gtm_uint8) NON_GTM64_ONLY(unsigned int) gtm_msize_t;

/* Each allocated block has the following structure. The actual address
   returned to the user for 'malloc' and supplied by the user for 'free'
   is actually the storage beginning at the 'userStorage.userStart' area.
   This holds true even for storage that is truely malloc'd. Note that true
   allocated length is kept even in the pro header.
*/
typedef struct storElemStruct
{	/* While the following chars and short are not the best for performance, they enable us
	   to keep the header size to 8 bytes in a pro build. This is important since our minimum
	   allocation size is 16 bytes leaving 8 bytes for data. Also I have not researched what
	   they are, there are a bunch of 8 byte allocates in GT.M that if we were to go to a 16
	   byte header would make the minimum block size 32 bytes thus doubling the storage
	   requirements for these small blocks. SE 03/2002 [Note 16 byte header is the norm in 64 bit]
	*/
	signed char	queueIndex;			/* Index into TwoTable for this size of element */
	unsigned char	state;				/* State of this block */
	unsigned short	extHdrOffset;			/* For MAXTWO sized elements: offset to the
							   header that describes the extent */
	GTM64_ONLY(char filler[4];) 			/* Explicit filler to align the length - may be repurposed */
	gtm_msize_t	realLen;			/* Real (total) length of allocation */
#ifdef DEBUG
	struct	storElemStruct	*fPtr;			/* Next storage element on free/allocated queue */
	struct	storElemStruct	*bPtr;			/* Previous storage element on free/allocated queue */
	unsigned char	*allocatedBy;			/* Who allocated storage */
	gtm_msize_t	allocLen;			/* Requested length of allocation */
	gtm_msize_t	smTn;				/* Storage management transaction number allocated at */
	unsigned char	headMarker[GTM64_ONLY(8)NON_GTM64_ONLY(4)];	/* Header that should not be modified during usage */
	union
	{
		struct storElemStruct *deferFreeNext;	/* Pointer to next deferred free block */
		unsigned char	userStart;		/* First byte of user useable storage */
	} userStorage;
#else
	union						/* In production mode, the links are used only when element is free */
	{
		struct storElemStruct *deferFreeNext;	/* Pointer to next deferred free block */
		struct					/* Free block information */
		{
			struct	storElemStruct	*fPtr;	/* Next storage element on free queue */
			struct	storElemStruct	*bPtr;	/* Previous storage element on free queue */
		} links;
		unsigned char	userStart;		/* First byte of user useable storage */
	} userStorage;
#endif
} storElem;

size_t gtm_bestfitsize(size_t);
void verifyFreeStorage(void);
void verifyAllocatedStorage(void);
void raise_gtmmemory_error(void);
void printMallocInfo(void);
void printMallocDump(void);

/* When verifying the storage chains, check the allocated chain first in case overruns for allocated storage
 * have damaged the free chains. This way we find the culprit rather than the symptom. Of course, in the case
 * where free'd storage is continued to be used, this method breaks down but it is hoped the chosen way finds
 * the greater number of issues rather than their symptoms.
 */
#define VERIFY_STORAGE_CHAINS			\
{						\
	GBLREF uint4	gtmDebugLevel;		\
	if (GDL_SmAllocVerf & gtmDebugLevel)	\
		verifyAllocatedStorage();	\
	if (GDL_SmFreeVerf & gtmDebugLevel)	\
		verifyFreeStorage();		\
}

#endif /* GTM_MALLOC_H__included */
