C/C++内存终极处理方法(夸张点,推荐)

C/C++内存终极处理方法(夸张点,推荐)
    C/C++动态分配给我们带来了很多方便,但同时,也给我们带来了无限的烦恼。
    1. 在嵌入式中
    嵌入式开发内存本来就不是很足够,过于频繁的动态生成和释放,导致内存碎片过多占用内存。最终降低了程序性能和稳定性。
    2. 在比较大型或自己不是很了解的源码中
    内存泄漏的问题在C/C++编程中是经常要面对的,对于自己比较了解或层次比较清晰的程序,查出内存泄漏并修改,那是比较简单的问题。但是当遇到的是自己不怎么了解或层次不清晰的程序时,就算我们找到在哪里泄漏,也很难在适当的地方对它进行释放
     那这时候我们怎么办呢?
    最好就是自己分配一块比较大的内存,自己管理这块内存,到最后自己再将整块内存释放掉。就是说一开始就分配好一块比较大的内存,当需要内存时,直接取这块内存其中的一部分,不需要时再放回,到程序结束时,再统一释放。
     以下是一份上面的实现模块程序和使用方法,只要将程序包含在你的程序中,并按照使用方法使用。应该可以对内存管理和保存起到一定作用。
    使用方法:
    //初始化,一般在程序的开始时
    MEMCTXT demo_mem_ctxt;
    initContext (&demo_mem_ctxt);
    //当需要分配内存时调用
    memAlloc(&demo_mem_ctxt ,size);
    //当需要更新分配内存时调用
    memRealloc(&demo_mem_ctxt, size);
    //当要释放内存时调用
    memFreePtr(&demo_mem_ctxt , ptr);
    //当程序退出时,真正释放内存
    freeContext (&demo_mem_ctxt);
    使用挺简单的,也可参照common.h文件使用,里面写得比较清楚,
    以下是要包含的程序文件(common.h, memheap.h, memheap.c)
Common.h
/*
*
* Any redistributions of this file including modified versions must
* maintain this copyright notice.
*
*****************************************************************************/
/**
* @file common.h
* Common ASN.1 runtime constants, data structure definitions, and run-time
* functions to support ASN.1 PER encoding/decoding as defined in the
* ITU-T standards.
*/
#ifndef _COMMON_H_
#define _COMMON_H_

#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>

/**
* @defgroup cruntime C Runtime Common Functions
* @{
*/


#define RT_MH_DONTKEEPFREE 0x1

#define OSRTMH_PROPID_DEFBLKSIZE 1
#define OSRTMH_PROPID_SETFLAGS 2
#define OSRTMH_PROPID_CLEARFLAGS 3

#define OSRTMH_PROPID_USER 10
/* Error Code Constants */

#define ASN_OK 0 /* normal completion status */
#define ASN_E_INVPARAM -30 /* invalid parameter */
#define ASN_E_NOMEM -12 /* no dynamic memory available */
/* ASN.1 Primitive Type Definitions */

//typedef char ASN1CHAR;
typedef unsigned char ASN1OCTET;
typedef ASN1OCTET ASN1BOOL;
typedef signed char ASN1INT8;
typedef unsigned char ASN1UINT8;
typedef int ASN1INT;
typedef unsigned int ASN1UINT;
typedef short ASN1SINT;
typedef unsigned short ASN1USINT;

//typedef ASN1UINT ASN1TAG;
#ifndef ASN1INT64

#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || /
defined(_WIN32)
#define ASN1INT64 __int64

#elif defined(__IBMC__) || defined(__GNUC__) || defined(__SUNPRO_C) || /
defined(__SUNPRO_CC) || defined(__CC_ARM) || /
defined(__HPUX_CC__) || defined(__HP_aCC)
#define ASN1INT64 long long

#else /* !MSC_VER && !__IBMC__ etc */
#define ASN1INT64 long

#endif
#endif /* ASN1INT64 */

#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif



#define XM_K_MEMBLKSIZ (8*1024)

/* Flag mask constant values */

#define ASN1DYNCTXT 0x8000
#define ASN1INDEFLEN 0x4000
#define ASN1TRACE 0x2000
#define ASN1LASTEOC 0x1000
#define ASN1FASTCOPY 0x0800 /* turns on the "fast copy" mode */
#define ASN1CONSTAG 0x0400 /* form of last parsed tag */
#define ASN1CANXER 0x0200 /* canonical XER */
#define ASN1SAVEBUF 0x0100 /* do not free dynamic encode buffer */
#define ASN1OPENTYPE 0x0080 /* item is an open type field */

/* ASN.1 encode/decode context block structure */

struct EventHandler;

typedef struct MEMCTXT { /* context block */
void* pMsgMemHeap; /* internal message memory heap */
void* pTypeMemHeap; /* memory heap */

} MEMCTXT;

/* macros and function prototypes */

#ifndef ASN1MAX
#define ASN1MAX(a,b) (((a)>(b))?(a):(b))
#endif

#ifndef ASN1MIN
#define ASN1MIN(a,b) (((a)<(b))?(a):(b))
#endif

/**
* @defgroup mem Memory Allocation Macros and Functions
* @ingroup cruntime
*
* Memory allocation functions and macros handle memory management for the
* ASN1C run-time. Special algorithms are used for allocation and deallocation
* of memory to improve the run-time performance. @{
*/
/**
* Allocate a dynamic array. This macro allocates a dynamic array of records of
* the given type. This version of the macro will return the ASN_E_NOMEM error
* status if the memory request cannot be fulfilled.
*
* @param pctxt - Pointer to a context block
* @param pseqof - Pointer to a generated SEQUENCE OF array structure.
* The <i>n</i> member variable must be set to the number
* of records to allocate.
* @param type - Data type of an array record
*/
#define ALLOC_ASN1ARRAY(pctxt,pseqof,type) do {/
if (sizeof(type)*(pseqof)->n < (pseqof)->n) return ASN_E_NOMEM; /
if (((pseqof)->elem = (type*) memHeapAlloc /
(&(pctxt)->pTypeMemHeap, sizeof(type)*(pseqof)->n)) == 0) return ASN_E_NOMEM; /
} while (0)

/**
* Allocate and zero an ASN.1 element. This macro allocates and zeros a single
* element of the given type.
*
* @param pctxt - Pointer to a context block
* @param type - Data type of record to allocate
*/
#define ALLOC_ASN1ELEM(pctxt,type) /
(type*) memHeapAllocZ (&(pctxt)->pTypeMemHeap, sizeof(type))

/**
* Allocate memory. This macro allocates the given number of bytes. It is
* similar to the C /c malloc run-time function.
*
* @param pctxt - Pointer to a context block
* @param nbytes - Number of bytes of memory to allocate
* @return - Void pointer to allocated memory or NULL if
* insufficient memory was available to fulfill the
* request.
*/
#define ASN1MALLOC(pctxt,nbytes) /
memHeapAlloc(&(pctxt)->pTypeMemHeap, nbytes)

/**
* Free memory associated with a context. This macro frees all memory held
* within a context. This is all memory allocated using the ASN1MALLOC (and
* similar macros) and the mem memory allocation functions using the given
* context variable.
*
* @param pctxt - Pointer to a context block
*/
#define ASN1MEMFREE(pctxt) /
memHeapFreeAll(&(pctxt)->pTypeMemHeap)

/**
* Free memory pointer. This macro frees memory at the given pointer. The
* memory must have been allocated using the ASN1MALLOC (or similar) macros or
* the mem memory allocation functions. This macro is similar to the C /c
* free function.
*
* @param pctxt - Pointer to a context block
* @param pmem - Pointer to memory block to free. This must have been
* allocated using the ASN1MALLOC macro or the
* memHeapAlloc function.
*/
#define ASN1MEMFREEPTR(pctxt,pmem) /
memHeapFreePtr(&(pctxt)->pTypeMemHeap, (void*)pmem)

/**
* @}
*/
#define ASN1BUFCUR(cp) (cp)->buffer.data[(cp)->buffer.byteIndex]
#define ASN1BUFPTR(cp) &(cp)->buffer.data[(cp)->buffer.byteIndex]

#ifdef __cplusplus
extern "C" {
#endif

#ifndef EXTERN
#ifdef MAKE_DLL
#define EXTERN __declspec(dllexport)
#elif defined (USEASN1DLL)
#define EXTERN __declspec(dllimport)
#else
#define EXTERN
#endif /* MAKE_DLL */
#endif /* EXTERN */

#ifndef _NO_MALLOC
#define ASN1CRTMALLOC0(nbytes) malloc(nbytes)
#define ASN1CRTFREE0(ptr) free(ptr)
#else

#ifdef _NO_THREADS
extern EXTERN MEMCTXT g_ctxt;

#define ASN1CRTMALLOC0(nbytes) memAlloc(&g_ctxt,(nbytes))
#define ASN1CRTFREE0(ptr) memFreePtr(&g_ctxt,(ptr))
#else
#define ASN1CRTMALLOC0(nbytes) (void*)0
#define ASN1CRTFREE0(ptr) (void*)0

#endif /* _NO_THREADS */
#endif /* _NO_MALLOC */

#define ASN1CRTMALLOC memHeapAlloc
#define ASN1CRTFREE ASN1MEMFREEPTR

/* Function prototypes */

#define DE_INCRBITIDX(pctxt) /
((--(pctxt)->buffer.bitOffset < 0) ? /
((++(pctxt)->buffer.byteIndex >= (pctxt)->buffer.size) ? ASN_E_ENDOFBUF : /
((pctxt)->buffer.bitOffset = 7, ASN_OK)) : ASN_OK)


#define DE_BIT(pctxt,pvalue) /
((DE_INCRBITIDX (pctxt) != ASN_OK) ? ASN_E_ENDOFBUF : ((pvalue) ? /
((*(pvalue) = (((pctxt)->buffer.data[(pctxt)->buffer.byteIndex]) & /
(1 << (pctxt)->buffer.bitOffset)) != 0), ASN_OK) : ASN_OK ))



/**
* This function assigns a buffer to a context block. The block should have
* been previously initialized by initContext.
*
* @param pctxt The pointer to the context structure variable to be
* initialized.
* @param bufaddr For encoding, the address of a memory buffer to receive
* and encode a message. For decoding the address of a
* buffer that contains the message data to be decoded.
* This address will be stored within the context
* structure. For encoding it might be zero, the dynamic
* buffer will be used in this case.
* @param bufsiz The size of the memory buffer. For encoding, it might be
* zero; the dynamic buffer will be used in this case.
* @return Completion status of operation:
* - 0 (ASN_OK) = success,
* - negative return value is error.
*/
EXTERN int initContextBuffer
(MEMCTXT* pctxt, const ASN1OCTET* bufaddr, ASN1UINT bufsiz);

/**
* This function initializes a context block. It makes sure that if the block
* was not previosly initialized, that all key working parameters are set to
* thier correct initial state values (i.e. declared within a function as a
* normal working variable), it is required that they invoke this function
* before using it.
*
* @param pctxt The pointer to the context structure variable to be
* initialized.
* @return Completion status of operation:
* - 0 (ASN_OK) = success,
* - negative return value is error.
*/
EXTERN int initContext (MEMCTXT* pctxt);

/**
* This function frees all dynamic memory associated with a context. This
* includes all memory inside the block (in particular, the list of memory
* blocks used by the mem functions).
*
* @param pctxt A pointer to a context structure.
*/
EXTERN void freeContext (MEMCTXT* pctxt);

/**
* This function allocates a new OOCTXT block and initializes it. Although
* the block is allocated from the standard heap, it should not be freed using
* free. The freeContext function should be used because this frees items
* allocated within the block before freeing the block itself.
*
* @return Pointer to newly created context
*/
EXTERN MEMCTXT* newContext (void);
/**
* @addtogroup rtmem
* @{
*/
/**
* Allocate memory. This macro allocates the given number of bytes. It is
* similar to the C /c malloc run-time function.
*
* @param pctxt - Pointer to a context block
* @param nbytes - Number of bytes of memory to allocate
* @return - Void pointer to allocated memory or NULL if insufficient memory
* was available to fulfill the request.
*/
#define memAlloc(pctxt,nbytes) /
memHeapAlloc(&(pctxt)->pTypeMemHeap,nbytes)

/**
* Allocate and zero memory. This macro allocates the given number of bytes
* and then initializes the memory block to zero.
*
* @param pctxt - Pointer to a context block
* @param nbytes - Number of bytes of memory to allocate
* @return - Void pointer to allocated memory or NULL if insufficient memory
* was available to fulfill the request.
*/
#define memAllocZ(pctxt,nbytes) /
memHeapAllocZ(&(pctxt)->pTypeMemHeap,nbytes)

/**
* Reallocate memory. This macro reallocates a memory block (either
* expands or contracts) to the given number of bytes. It is
* similar to the C /c realloc run-time function.
*
* @param pctxt - Pointer to a context block
* @param mem_p - Pointer to memory block to reallocate. This must have been
* allocated using the memHeapAlloc macro or the memHeapAlloc function.
* @param nbytes - Number of bytes of memory to which the block is to be
* resized.
* @return - Void pointer to allocated memory or NULL if insufficient memory
* was available to fulfill the request. This may be the same as the pmem
* pointer that was passed in if the block did not need to be relocated.
*/
#define memRealloc(pctxt,mem_p,nbytes) /
memHeapRealloc(&(pctxt)->pTypeMemHeap, (void*)mem_p, nbytes)

/**
* Free memory pointer. This macro frees memory at the given pointer.
* The memory must have been allocated using the memHeapAlloc (or similar)
* macros or the mem memory allocation macros. This macro is
* similar to the C /c free function.
*
* @param pctxt - Pointer to a context block
* @param mem_p - Pointer to memory block to free. This must have
* been allocated using the memHeapAlloc or memAlloc macro or the
* memHeapAlloc function.
*/
#define memFreePtr(pctxt,mem_p) /
if (memHeapCheckPtr (&(pctxt)->pTypeMemHeap, (void*)mem_p)) /
memHeapFreePtr(&(pctxt)->pTypeMemHeap, (void*)mem_p)

/**
* Free memory associated with a context. This macro frees all memory
* held within a context. This is all memory allocated using the
* memHeapAlloc (and similar macros) and the mem memory allocation
* functions using the given context variable.
*
* @param pctxt - Pointer to a context block
*/
#define memFree(pctxt) /
memHeapFreeAll(&(pctxt)->pTypeMemHeap)

/**
* Reset memory associated with a context. This macro resets all memory
* held within a context. This is all memory allocated using the memHeapAlloc
* (and similar macros) and the mem memory allocation functions using the
* given context variable.
*
* <p>The difference between this and the ASN1MEMFREE macro is that the
* memory blocks held within the context are not actually freed. Internal
* pointers are reset so the existing blocks can be reused. This can
* provide a performace improvement for repetitive tasks such as decoding
* messages in a loop.
*
* @param pctxt - Pointer to a context block
*/
#define memReset(pctxt) /
memHeapReset(&(pctxt)->pTypeMemHeap)

/* Alias for __cdecl modifier; if __cdecl keyword is not supported,
* redefine it as empty macro. */

#if !defined(OSCDECL)
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define OSCDECL __cdecl
#else
#define OSCDECL
#endif
#endif /* OSCDECL */

/* Pointers to C Run-Time memory allocation functions *
* (See memSetAllocFuncs) */

typedef void *(OSCDECL *OSMallocFunc ) (size_t size);
typedef void *(OSCDECL *OSReallocFunc) (void *ptr, size_t size);
typedef void (OSCDECL *OSFreeFunc ) (void *ptr);

EXTERN void memHeapAddRef (void** ppvMemHeap);
EXTERN void* memHeapAlloc (void** ppvMemHeap, int nbytes);
EXTERN void* memHeapAllocZ (void** ppvMemHeap, int nbytes);
EXTERN int memHeapCheckPtr (void** ppvMemHeap, void* mem_p);
EXTERN int memHeapCreate (void** ppvMemHeap);
EXTERN void memHeapFreeAll (void** ppvMemHeap);
EXTERN void memHeapFreePtr (void** ppvMemHeap, void* mem_p);
EXTERN void* memHeapRealloc (void** ppvMemHeap, void* mem_p, int nbytes_);
EXTERN void memHeapRelease (void** ppvMemHeap);
EXTERN void memHeapReset (void** ppvMemHeap);

EXTERN void* memHeapMarkSaved
(void** ppvMemHeap, const void* mem_p, ASN1BOOL saved);

EXTERN void memHeapSetProperty
(void** ppvMemHeap, ASN1UINT propId, void* pProp);


/**
* This function sets the pointers to standard allocation functions. These
* functions are used to allocate/reallocate/free the memory blocks. By
* default, standard C functions - 'malloc', 'realloc' and 'free' - are used.
* But if some platforms do not support these functions (or some other reasons
* exist) they can be overloaded. The functions being overloaded should have
* the same prototypes as standard ones.
*
* @param malloc_func Pointer to the memory allocation function ('malloc' by
* default).
* @param realloc_func Pointer to the memory reallocation function ('realloc'
* by default).
* @param free_func Pointer to the memory deallocation function ('free' by
* default).
*/
EXTERN void memSetAllocFuncs (OSMallocFunc malloc_func,
OSReallocFunc realloc_func,
OSFreeFunc free_func);


/*
* This function sets flags to a heap. May be used to control the heap's
* behavior.
*
* @param pctxt Pointer to a memory block structure that contains the
* list of dynamic memory block maintained by these
* functions.
* @param flags The flags.
*/
EXTERN void memHeapSetFlags (MEMCTXT* pctxt, ASN1UINT flags);

/*
* This function clears memory heap flags.
*
* @param pctxt Pointer to a memory block structure that contains the
* list of dynamic memory block maintained by these
* functions.
* @param flags The flags
*/
EXTERN void memHeapClearFlags (MEMCTXT* pctxt, ASN1UINT flags);

/**
* This function sets the pointer to standard allocation functions. These
* functions are used to allocate/reallocate/free the memory blocks. By
* default, standard C functions - malloc, realloc, and free - are used. But if
* some platforms do not support these functions or some other reasons exist)
* they can be overloaded. The functions being overloaded should have the same
* prototypes as standard ones.
*
* @param pctxt Pointer to a context block.
* @param blkSize The currently used minimum size and the granularity of
* memory blocks.
*/

EXTERN void memHeapSetDefBlkSize (MEMCTXT* pctxt, ASN1UINT blkSize);

/**
* This function returns the actual granularity of memory blocks.
*
* @param pctxt Pointer to a context block.
*/
EXTERN ASN1UINT memHeapGetDefBlkSize (MEMCTXT* pctxt);

#ifdef _STATIC_HEAP
EXTERN void memSetStaticBuf (void* memHeapBuf, ASN1UINT blkSize);
#endif

/* PER encode/decode related items */

#define INCRBITIDX(pctxt) /
((--(pctxt)->buffer.bitOffset < 0) ? /
((++(pctxt)->buffer.byteIndex >= (pctxt)->buffer.size) ? ASN_E_ENDOFBUF : /
((pctxt)->buffer.bitOffset = 7, ASN_OK)) : ASN_OK)

#define DECODEBIT(pctxt,pvalue) /
((INCRBITIDX (pctxt) != ASN_OK) ? ASN_E_ENDOFBUF : ((pvalue) ? /
((*(pvalue) = (((pctxt)->buffer.data[(pctxt)->buffer.byteIndex]) & /
(1 << (pctxt)->buffer.bitOffset)) != 0), ASN_OK) : ASN_OK ))


#ifdef __cplusplus
}
#endif

#endif

memheap.h
/*

* Any redistributions of this file including modified versions must
* maintain this copyright notice.
*
*****************************************************************************/

#ifndef __RTMEMHEAP_HH__
#define __RTMEMHEAP_HH__

#include "common.h"

/* internal heap flags */
#define RT_MH_INTERNALMASK 0xF0000000u
#define RT_MH_FREEHEAPDESC 0x10000000u

typedef struct OSMemLink {
struct OSMemLink* pnext;
struct OSMemLink* pprev;
struct OSMemLink* pnextRaw; /* next RAW block */
void* pMemBlk;
ASN1OCTET blockType; /* 1 = standard, 2 = raw (see RTMEM* flags) */
} OSMemLink;

/* MemLink blockTypes */
#define RTMEMSTD 0x0001
#define RTMEMRAW 0x0002
#define RTMEMMALLOC 0x0004
#define RTMEMSAVED 0x0008
#define RTMEMLINK 0x0010 /* contains MemLink */

/* ASN.1 memory allocation structures */

typedef struct OSMemHeap {
OSMemLink* phead;
ASN1UINT usedUnits;
ASN1UINT usedBlocks;
ASN1UINT freeUnits;
ASN1UINT freeBlocks;
ASN1UINT keepFreeUnits;
ASN1UINT defBlkSize;
ASN1UINT refCnt;
ASN1UINT flags;
} OSMemHeap;

/* see rtMemDefs.c file */
extern ASN1UINT g_defBlkSize;
extern OSMallocFunc g_malloc_func;
extern OSReallocFunc g_realloc_func;
extern OSFreeFunc g_free_func;

#endif /* __RTMEMHEAP_HH__ */

Memheap.c
/*

* Any redistributions of this file including modified versions must
* maintain this copyright notice.
*
*****************************************************************************/

#include <stdlib.h>
#include "memheap.h"

ASN1UINT g_defBlkSize = XM_K_MEMBLKSIZ;
OSMallocFunc g_malloc_func = malloc;
#ifndef _NO_REALLOC
OSReallocFunc g_realloc_func = realloc;
#else
OSReallocFunc g_realloc_func = 0;
#endif
OSFreeFunc g_free_func = free;

static OSMemLink* memHeapAddBlock (OSMemLink** ppMemLink,
void* pMemBlk, int blockType);

typedef void OSMemElemDescr;


#define pElem_flags(pElem) (*((ASN1OCTET*)pElem))
#define pElem_nunits(pElem) (*((ASN1USINT*)(((ASN1OCTET*)pElem)+2)))
#define pElem_prevOff(pElem) (*((ASN1USINT*)(((ASN1OCTET*)pElem)+4)))
#define pElem_nextFreeOff(pElem) (*((ASN1USINT*)(((ASN1OCTET*)pElem)+6)))
#define pElem_beginOff(pElem) (*((ASN1USINT*)(((ASN1OCTET*)pElem)+6)))
#define sizeof_OSMemElemDescr 8
#define pElem_data(pElem) (((ASN1OCTET*)pElem)+sizeof_OSMemElemDescr)

typedef struct MemBlk {
OSMemLink* plink;
ASN1USINT free_x; /* index of free space at end of block */
ASN1USINT freeMem; /* size of free space before free_x */
ASN1USINT nunits; /* size of data */
ASN1USINT lastElemOff; /* last element offset in block */
ASN1USINT freeElemOff; /* first free element offset in block */
ASN1USINT nsaved; /* num of saved elems in the block */

ASN1USINT spare[2]; /* forces alignment on 8-bytes boundary,
for 64-bit systems */
char data[8];
} OSMemBlk;

/* Macros for operations with memory blocks */

#define QOFFSETOF(pElem, pPrevElem) /
((ASN1USINT)(((unsigned)((char*)pElem - (char*)pPrevElem)) >> 3u))

#define OFFSETOF(pElem, pPrevElem) /
((ASN1UINT)((char*)pElem - (char*)pPrevElem))

#define ISFREE(pElem) (pElem_flags(pElem) & 1)
#define SET_FREE(pElem) (pElem_flags(pElem) |= 1)
#define CLEAR_FREE(pElem) (pElem_flags(pElem) &= (~1))

#define ISLAST(pElem) (pElem_flags(pElem) & 2)
#define SET_LAST(pElem) (pElem_flags(pElem) |= 2)
#define CLEAR_LAST(pElem) (pElem_flags(pElem) &= (~2))

#define ISSAVED(pElem) (pElem_flags(pElem) & 4)
#define SET_SAVED(pMemBlk,pElem) do { /
(pElem_flags (pElem) |= 4); pMemBlk->nsaved++; } while (0)
#define CLEAR_SAVED(pMemBlk,pElem) do { /
(pElem_flags (pElem) &= (~4)); pMemBlk->nsaved--; } while (0)

#define ISFIRST(pElem) (int)(pElem_prevOff (pElem) == 0)

#define GETPREV(pElem) /
((pElem_prevOff (pElem) == 0) ? 0 : /
((OSMemElemDescr*) (((char*)pElem) - (pElem_prevOff (pElem) * 8u))))

#define GETNEXT(pElem) /
((ISLAST (pElem)) ? 0 : /
((OSMemElemDescr*)(((char*)pElem) + ((pElem_nunits (pElem) + 1) * 8u))))

#define GET_NEXT_FREE(pElem) /
((pElem_nextFreeOff (pElem) == 0) ? 0 : /
((OSMemElemDescr*) (((char*)pElem) + (pElem_nextFreeOff (pElem) * 8u))))

#define GET_MEMBLK(pElem) /
((OSMemBlk*) (((char*)pElem) - (pElem_beginOff (pElem) * 8u) - /
sizeof (OSMemBlk) + sizeof ((OSMemBlk*)0)->data))

#define GET_LAST_ELEM(pMemBlk) /
((pMemBlk->lastElemOff == 0) ? 0 : /
(OSMemElemDescr*)&pMemBlk->data[(pMemBlk->lastElemOff - 1) * 8u])

#define SET_LAST_ELEM(pMemBlk, pElem) /
pMemBlk->lastElemOff = (ASN1USINT)((pElem == 0) ? 0 : /
(SET_LAST (pElem), (QOFFSETOF (pElem, pMemBlk->data) + 1)))

#define GET_FREE_ELEM(pMemBlk) /
((pMemBlk->freeElemOff == 0) ? 0 : /
(OSMemElemDescr*)&pMemBlk->data[(pMemBlk->freeElemOff - 1) * 8u])

#define FORCE_SET_FREE_ELEM(pMemBlk, pElem) do { /
if (pElem == 0) { pMemBlk->freeElemOff = 0; break; } /
SET_FREE (pElem); /
pMemBlk->freeElemOff = (ASN1USINT)(QOFFSETOF (pElem, pMemBlk->data) + 1); /
} while (0)

#define SET_FREE_ELEM(pMemBlk, pElem) setLastElem (pMemBlk, pElem)

/* Memory debugging macros */
#define RTMEMDIAG1(msg)
#define RTMEMDIAG2(msg,a)
#define RTMEMDIAG3(msg,a,b)
#define RTMEMDIAG4(msg,a,b,c)
#define FILLFREEMEM(mem,size)
#define FILLNEWMEM(mem,size)

#define CHECKMEMELEM(memblk,elem)
#define CHECKMEMBLOCK(memheap,memblk)
#define CHECKMEMHEAP(memheap)
#define TRACEMEMELEM(memblk, elem, name)
#define TRACEFREE(memlink,name)



int initContext (MEMCTXT* pctxt)
{
memset (pctxt, 0, sizeof(MEMCTXT));

memHeapCreate (&pctxt->pTypeMemHeap);
pctxt->pMsgMemHeap =pctxt->pTypeMemHeap;
memHeapAddRef (&pctxt->pMsgMemHeap);

return ASN_OK;
}

void freeContext (MEMCTXT* pctxt)
{
memHeapRelease (&pctxt->pTypeMemHeap);
memHeapRelease (&pctxt->pMsgMemHeap);
}


static void setLastElem (OSMemBlk* pMemBlk, OSMemElemDescr* pElem)
{
if (pElem == 0) {
pMemBlk->freeElemOff = 0;
return;
}
else if (ISLAST (pElem))
return;
else if (pMemBlk->freeElemOff > QOFFSETOF (pElem, pMemBlk->data) + 1) {
pElem_nextFreeOff (pElem) = QOFFSETOF (GET_FREE_ELEM (pMemBlk), pElem);
FORCE_SET_FREE_ELEM (pMemBlk, pElem);
}
else if (pMemBlk->freeElemOff == 0) {
pElem_nextFreeOff (pElem) = 0;
FORCE_SET_FREE_ELEM (pMemBlk, pElem);
}
else {
SET_FREE (pElem);
pElem_nextFreeOff (pElem) = 0;
}
}

void* memHeapAlloc (void** ppvMemHeap, int nbytes)
{
OSMemHeap* pMemHeap;
OSMemLink* pMemLink, **ppMemLink;
OSMemBlk* pMemBlk = 0;
void* mem_p = NULL;
unsigned remUnits;
ASN1UINT nunits;

if (ppvMemHeap == 0)
return 0;

if (*ppvMemHeap == 0)
if (memHeapCreate (ppvMemHeap) != ASN_OK)
return 0;

/* Round number of bytes to nearest 8-byte boundary */

nunits = (((unsigned)(nbytes + 7)) >> 3);

pMemHeap = (OSMemHeap*) *ppvMemHeap;
ppMemLink = &pMemHeap->phead;

/* if size is greater than 2**19, then allocate as RAW block */

if (nunits > (1<<16) - 2) {
void *data;

/* allocate raw block */

data = g_malloc_func (nbytes);
if (data == NULL) {
return NULL;
}
pMemLink = memHeapAddBlock (ppMemLink, data, RTMEMMALLOC | RTMEMRAW);
if (pMemLink == 0) {
g_free_func (data);
return NULL;
}
/* save size of the RAW memory block behind the pMemLink */
*(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = nbytes;
return data;
}

RTMEMDIAG2 ("memHeapAlloc: adjusted nbytes = %d/n", nbytes);

/* Try to allocate a slot from an existing block on the list */

for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnext) {
if (pMemLink->blockType & RTMEMRAW) continue;
else pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;

remUnits = pMemBlk->nunits - pMemBlk->free_x;

if ((unsigned)(nunits + 1) <= remUnits) {
OSMemElemDescr* pElem = (OSMemElemDescr*)
&pMemBlk->data [((ASN1UINT)pMemBlk->free_x) * 8u];
OSMemElemDescr* pPrevElem;

RTMEMDIAG1 ("memHeapAlloc: found existing slot../n");

/* if block is clean, set some vars in heap */
if (pMemBlk->free_x == 0) {
pMemHeap->freeUnits -= pMemBlk->nunits;
pMemHeap->freeBlocks--;
}

pElem_flags (pElem) = 0;
if (pMemBlk->lastElemOff != 0)
pElem_prevOff (pElem) =
(ASN1USINT)(pMemBlk->free_x - pMemBlk->lastElemOff + 1);
else
pElem_prevOff (pElem) = 0;

pPrevElem = GET_LAST_ELEM (pMemBlk);
if (pPrevElem != 0)
CLEAR_LAST (pPrevElem);

pElem_nunits (pElem) = (ASN1USINT)nunits;
pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);
pMemBlk->lastElemOff = (ASN1USINT)(pMemBlk->free_x + 1);

mem_p = (void*) (pElem_data (pElem));

/* sizeof (OSMemElemDescr) == 1 unit */
pMemBlk->free_x += nunits + 1;

SET_LAST_ELEM (pMemBlk, pElem);

FILLNEWMEM (mem_p, nunits * 8u);
TRACEMEMELEM(pMemBlk, pElem, "Allocated");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
break;
}
}

/* If not successful, look for empty elements in existing blocks */

if (0 == mem_p) {
for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnext) {
if (pMemLink->blockType & RTMEMRAW) continue;

pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;

if (nunits <= (ASN1UINT)pMemBlk->freeMem) {
OSMemElemDescr* pElem = GET_FREE_ELEM(pMemBlk), *pPrevFree = 0;

RTMEMDIAG2
("memHeapAlloc: try to reuse empty elems in pMemBlk = 0x%x.../n",
pMemBlk);

while (pElem != 0) {
if (ISFREE (pElem)) {
if (nunits <= (ASN1UINT)pElem_nunits (pElem)) {
RTMEMDIAG3
("memHeapAlloc: "
"found an exisiting free element 0x%x, size %d/n",
pElem, (pElem_nunits (pElem) * 8u));

if (pMemBlk->freeElemOff ==
QOFFSETOF (pElem, pMemBlk->data) + 1)
{

/* modify the pMemBlk->freeElemOff value if necsry */

OSMemElemDescr* nextFree = GET_NEXT_FREE (pElem);
FORCE_SET_FREE_ELEM (pMemBlk, nextFree);
}
else if (pPrevFree != 0) {
OSMemElemDescr* pNextFree = GET_NEXT_FREE (pElem);
if (pNextFree != 0)
pElem_nextFreeOff (pPrevFree) = QOFFSETOF (pNextFree,
pPrevFree);
else
pElem_nextFreeOff (pPrevFree) = 0;
}

CLEAR_FREE (pElem);

/* set beginOff value */

pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);

pMemBlk->freeMem -= pElem_nunits (pElem);

CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);

mem_p = memHeapRealloc
(ppvMemHeap, pElem_data (pElem), nunits * 8u);
if (mem_p != 0) {
FILLNEWMEM (mem_p, nunits * 8u);
TRACEMEMELEM(pMemBlk, pElem, "Allocated");
}
break;
}
}
pPrevFree = pElem;
pElem = GET_NEXT_FREE (pElem);
}
if (mem_p != 0) break;
}
}
}

/* If not successful, malloc a new block and alloc from it */

if (!mem_p) {
ASN1UINT allocSize, dataUnits;
ASN1OCTET* pmem;
register ASN1UINT defBlkSize = pMemHeap->defBlkSize;

RTMEMDIAG1 ("memHeapAlloc: alloc block../n");

allocSize = (ASN1UINT) ((((ASN1UINT)nunits) * 8u) +
sizeof (OSMemBlk) + sizeof_OSMemElemDescr);
allocSize = (ASN1UINT) (allocSize < defBlkSize) ? defBlkSize :
((allocSize + defBlkSize - 1) / defBlkSize * defBlkSize);
dataUnits = (ASN1UINT)((allocSize - sizeof (OSMemBlk)) >> 3u);
if (dataUnits >= (1u<<16)) {
dataUnits = (ASN1UINT)((1u<<16) - 1);
allocSize = (ASN1UINT)
((((ASN1UINT)dataUnits) * 8u) + sizeof (OSMemBlk));
}

pmem = (ASN1OCTET*) g_malloc_func (allocSize + sizeof (OSMemLink));
if (0 != pmem) {
OSMemElemDescr* pElem;

pMemBlk = (OSMemBlk*) (pmem + sizeof (OSMemLink));
pElem = (OSMemElemDescr*)&pMemBlk->data[0];

mem_p = (void*) pElem_data (pElem);
pElem_nunits (pElem) = (ASN1USINT)nunits;
pElem_flags (pElem) = 0;
pElem_prevOff (pElem) = 0;
pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);

/* sizeof (OSMemElemDescr) == 1 unit */
pMemBlk->free_x = (ASN1USINT)(nunits + 1);

pMemBlk->freeMem = 0;
pMemBlk->nunits = (ASN1USINT)dataUnits;
SET_LAST_ELEM (pMemBlk, pElem);
pMemBlk->freeElemOff = 0;
pMemBlk->nsaved = 0;

if (memHeapAddBlock (ppMemLink, pMemBlk, RTMEMSTD | RTMEMLINK) == 0)
{
g_free_func (pmem);
return NULL;
}

/* set vars in heap */
pMemHeap->usedUnits += dataUnits;
pMemHeap->usedBlocks++;

FILLNEWMEM (mem_p, nunits * 8u);
TRACEMEMELEM(pMemBlk, pElem, "Allocated");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
}
else
return NULL;
}
RTMEMDIAG2 ("memHeapAlloc: pMemBlk = 0x%x/n", pMemBlk);
RTMEMDIAG2 ("memHeapAlloc: pMemBlk->free_x = %d/n", pMemBlk->free_x);
RTMEMDIAG2 ("memHeapAlloc: pMemBlk->size = %d/n",
pMemBlk->nunits * 8u);
RTMEMDIAG2 ("memHeapAlloc: mem_p = 0x%x/n", mem_p);
RTMEMDIAG2 ("memHeapAlloc: sizeof (short) = %d/n", sizeof(short));

return (mem_p);
}

void* memHeapAllocZ (void** ppvMemHeap, int nbytes)
{
void* ptr = memHeapAlloc (ppvMemHeap, nbytes);
if (0 != ptr) memset (ptr, 0, nbytes);
return ptr;
}

void memHeapFreePtr (void** ppvMemHeap, void* mem_p)
{
OSMemHeap* pMemHeap;
OSMemLink** ppMemLink;
OSMemElemDescr* pElem;
OSMemBlk* pMemBlk;
OSMemLink* pMemLink, *pPrevMemLink = 0;

RTMEMDIAG2 ("memHeapFreePtr: freeing mem_p = 0x%x/n", mem_p);

if (mem_p == 0 || ppvMemHeap == 0 || *ppvMemHeap == 0) return;

pMemHeap = *(OSMemHeap**)ppvMemHeap;
ppMemLink = &pMemHeap->phead;

/* look for chain of RAW blocks first */

for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
if ((pMemLink->blockType & RTMEMRAW) &&
pMemLink->pMemBlk == mem_p)
{
if(pMemLink->pnext != 0) {
pMemLink->pnext->pprev = pMemLink->pprev;
}
if(pMemLink->pprev != 0) {
pMemLink->pprev->pnext = pMemLink->pnext;
}
else { /* head */
*ppMemLink = pMemLink->pnext;
}
if (pPrevMemLink != 0)
pPrevMemLink->pnextRaw = pMemLink->pnextRaw;
else if (*ppMemLink != 0 && (*ppMemLink)->pnextRaw == 0 &&
*ppMemLink != pMemLink->pnextRaw)
{
(*ppMemLink)->pnextRaw = pMemLink->pnextRaw;
}
if ((pMemLink->blockType & RTMEMLINK) &&
(pMemLink->blockType & RTMEMMALLOC))
{
g_free_func (pMemLink);
}
else {
if (pMemLink->blockType & RTMEMMALLOC)
g_free_func (pMemLink->pMemBlk);
g_free_func (pMemLink);
}
return;
}
pPrevMemLink = pMemLink;
}

pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);
pMemBlk = GET_MEMBLK (pElem);

CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK(pMemHeap, pMemBlk);

if (ISFREE (pElem)) { /* already freed! */
RTMEMDIAG2 ("memHeapFreePtr: "
"the element 0x%x is already freed!/n", pElem);
return;
}

if (ISSAVED (pElem)) {
CLEAR_SAVED (pMemBlk, pElem);
if (pMemBlk->nsaved == 0)
pMemBlk->plink->blockType &= (~RTMEMSAVED);
}

TRACEMEMELEM(pMemBlk, pElem, "Freed");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK(pMemHeap, pMemBlk);

RTMEMDIAG2 ("memHeapFreePtr: pMemBlk = 0x%x/n", pMemBlk);
RTMEMDIAG2 ("memHeapFreePtr: pMemBlk->size = %d/n",
pMemBlk->nunits * 8u);

if (ISLAST (pElem)) { /* is it the last? */
OSMemElemDescr* pPrevElem = GETPREV (pElem);

CHECKMEMELEM (pMemBlk, pPrevElem);

pMemBlk->free_x -= (pElem_nunits (pElem) + 1);

FILLFREEMEM (&pMemBlk->data [pMemBlk->free_x * 8u],
(pElem_nunits (pElem) + 1) * 8u);

if (pPrevElem != 0 && ISFREE (pPrevElem)) {
OSMemElemDescr* pFreeElem;

pMemBlk->free_x -= (pElem_nunits (pPrevElem) + 1);
pMemBlk->freeMem -= pElem_nunits (pPrevElem);
SET_LAST_ELEM (pMemBlk, GETPREV (pPrevElem));

/* wasn't it the last elem in block? */
if (pMemBlk->lastElemOff != 0) {

/* correct nextFreeOff for previous free element */

pFreeElem = GET_FREE_ELEM (pMemBlk);
if (pFreeElem == pPrevElem) {
pMemBlk->freeElemOff = 0; /* it was the last free elem */
}
else {
OSMemElemDescr* pNextFree = 0;

while (pFreeElem < pPrevElem) {
pNextFree = pFreeElem;
pFreeElem = GET_NEXT_FREE (pFreeElem);
}
pElem_nextFreeOff (pNextFree) = 0;
}
}
}
else {
SET_LAST_ELEM (pMemBlk, pPrevElem);
}

RTMEMDIAG2 ("memHeapFreePtr: pMemBlk->free_x = %d/n",
pMemBlk->free_x);

/* The question is: do we really want to get rid of the */
/* block or should we keep it around for reuse? */
if (pMemBlk->lastElemOff == 0) { /* was it the last elem in block? */

if ((pMemHeap->flags & RT_MH_DONTKEEPFREE) ||
(pMemHeap->keepFreeUnits > 0 &&
pMemHeap->freeUnits + pMemBlk->nunits > pMemHeap->keepFreeUnits))
{
ASN1OCTET blockType = pMemBlk->plink->blockType;

/* we may free the block */

pMemHeap->usedUnits -= pMemBlk->nunits;
pMemHeap->usedBlocks --;

if(pMemBlk->plink->pnext != 0) {
pMemBlk->plink->pnext->pprev = pMemBlk->plink->pprev;
}
if(pMemBlk->plink->pprev != 0) {
pMemBlk->plink->pprev->pnext = pMemBlk->plink->pnext;
}
else { /* head */
if (pMemBlk->plink->pnext != 0 &&
!(pMemBlk->plink->pnext->blockType & RTMEMRAW))
{
pMemBlk->plink->pnext->pnextRaw = (*ppMemLink)->pnextRaw;
}
*ppMemLink = pMemBlk->plink->pnext;
}
FILLFREEMEM (pMemBlk->plink, sizeof (*pMemBlk->plink));
FILLFREEMEM (pMemBlk->data, (pMemBlk->nunits * 8u));

g_free_func (pMemBlk->plink);

if (!(blockType & RTMEMLINK)) {
FILLFREEMEM (pMemBlk, sizeof (*pMemBlk));
g_free_func (pMemBlk);
}
RTMEMDIAG2 ("memHeapFreePtr: pMemBlk = 0x%x was freed/n",
pMemBlk);
}
else {
/* reset pMemBlk for re-usage */
pMemBlk->free_x = 0;
pMemBlk->freeElemOff = 0;
pMemBlk->lastElemOff = 0;
pMemBlk->freeMem = 0;
pMemBlk->nsaved = 0;
pMemHeap->freeUnits += pMemBlk->nunits;
pMemHeap->freeBlocks ++;
}
}
else {
SET_LAST (GET_LAST_ELEM (pMemBlk));
FILLFREEMEM (((char*) &pMemBlk->data[0]) + (pMemBlk->free_x * 8u),
(pMemBlk->nunits - pMemBlk->free_x) * 8u);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
}
}
else { /* mark as free elem inside the block */
CHECKMEMBLOCK (pMemHeap, pMemBlk);

SET_FREE_ELEM(pMemBlk, pElem);

pMemBlk->freeMem += pElem_nunits (pElem);
RTMEMDIAG2 ("memHeapFreePtr: element 0x%x marked as free./n",
pElem);

/* try to unite free blocks, if possible */
if (!ISFIRST (pElem)) {
if (ISFREE (GETPREV (pElem))) {
OSMemElemDescr* prevelem_p = GETPREV (pElem);

/* +1 because the OSMemElemDescr has size ONE unit (8 bytes) */
pElem_nunits (prevelem_p) += pElem_nunits (pElem) + 1;

pElem = prevelem_p;
pMemBlk->freeMem ++; /* sizeof (OSMemElemDescr) == 1 unit */
}
else {
/* look for nearest previous free block to correct nextFreeOff */

OSMemElemDescr* prevelem_p = pElem;

do {
prevelem_p = GETPREV (prevelem_p);
}
while (prevelem_p && !ISFREE (prevelem_p));

if (prevelem_p != 0) {
OSMemElemDescr* pNextFree = GET_NEXT_FREE (prevelem_p);
if (pNextFree != 0)
pElem_nextFreeOff (pElem) = QOFFSETOF (pNextFree, pElem);
else
pElem_nextFreeOff (pElem) = 0;
pElem_nextFreeOff (prevelem_p) = QOFFSETOF (pElem, prevelem_p);

CHECKMEMELEM (pMemBlk, prevelem_p);
}
}
}
if (!ISLAST (pElem) && ISFREE (GETNEXT (pElem))) {
OSMemElemDescr* nextelem_p = GETNEXT (pElem);

/* +1 because the OSMemElemDescr has size ONE unit (8 bytes) */
pElem_nunits (pElem) += pElem_nunits (nextelem_p) + 1;

if (pElem_nextFreeOff (nextelem_p) == 0)
pElem_nextFreeOff (pElem) = 0;
else
pElem_nextFreeOff (pElem) =
QOFFSETOF (GET_NEXT_FREE (nextelem_p), pElem);
pMemBlk->freeMem ++;
}

/* correct the prevOff field of next element */
if (!ISLAST (pElem)) {
OSMemElemDescr* nextelem_p = GETNEXT (pElem);
pElem_prevOff (nextelem_p) = QOFFSETOF (nextelem_p, pElem);
}

CHECKMEMELEM (pMemBlk, pElem);
FILLFREEMEM (pElem_data (pElem), (pElem_nunits (pElem) * 8u));
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
}
}

static void initNewFreeElement (OSMemBlk* pMemBlk,
OSMemElemDescr* pNewElem, OSMemElemDescr* pElem)
{
OSMemElemDescr *pNextElem, *pPrevElem = 0;

/* create new free element on the freed place */

pElem_flags (pNewElem) = 0;
SET_FREE (pNewElem);

pElem_prevOff (pNewElem) = QOFFSETOF (pNewElem, pElem);

if (pMemBlk->freeElemOff != 0 &&
pMemBlk->freeElemOff < QOFFSETOF (pElem, pMemBlk->data) + 1)
{
/* look for nearest previous free block to correct its nextFreeOff */

pPrevElem = pElem;

do {
pPrevElem = GETPREV (pPrevElem);
}
while (pPrevElem && !ISFREE (pPrevElem));
}
if (pPrevElem != 0) { /* if it is not first free element... */

/* correct nextFreeOff for prev free element */

pElem_nextFreeOff (pPrevElem) = QOFFSETOF (pNewElem, pPrevElem);
}
else { /* if it is first free element in the block */
FORCE_SET_FREE_ELEM (pMemBlk, pNewElem);
}

pNextElem = GETNEXT (pNewElem);
if (ISFREE (pNextElem)) {

/* if the next elem is free, then unite them together */

pElem_nunits (pNewElem) += pElem_nunits (pNextElem) + 1;
if (pElem_nextFreeOff (pNextElem) != 0)
pElem_nextFreeOff (pNewElem) = QOFFSETOF (GET_NEXT_FREE (pNextElem),
pNewElem);
else
pElem_nextFreeOff (pNewElem) = 0;
pMemBlk->freeMem++; /* +1 because space for MemElemDescr is freed now */
pNextElem = GETNEXT (pNewElem);
}
pElem_prevOff (pNextElem) = QOFFSETOF (pNextElem, pNewElem);

if (pMemBlk->freeElemOff != 0) {

/* look for the next nearest free elem */

pNextElem = GETNEXT (pNewElem);
while (pNextElem != 0 && !ISFREE (pNextElem))
pNextElem = GETNEXT (pNextElem);

/* set nextFreeOff for new element */

if (pNextElem != 0)
pElem_nextFreeOff (pNewElem) = QOFFSETOF (pNextElem, pNewElem);
else
pElem_nextFreeOff (pNewElem) = 0;
}
else
pElem_nextFreeOff (pNewElem) = 0;

}

void* memHeapRealloc (void** ppvMemHeap, void* mem_p, int nbytes_)
{
OSMemHeap* pMemHeap;
OSMemLink** ppMemLink;
OSMemBlk* pMemBlk;
OSMemElemDescr* pElem;
OSMemLink* pMemLink, *pPrevMemLink = 0;
void *newMem_p;
unsigned nbytes, nunits;

/* if mem_p == NULL - do rtMemAlloc */

if (ppvMemHeap == 0 || *ppvMemHeap == 0) return 0;

if (mem_p == 0) {
return memHeapAlloc (ppvMemHeap, nbytes_);
}

pMemHeap = *(OSMemHeap**)ppvMemHeap;
ppMemLink = &pMemHeap->phead;

/* look for chain of RAW blocks first */

for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
if ((pMemLink->blockType & RTMEMRAW) &&
pMemLink->pMemBlk == mem_p)
{
if (pMemLink->blockType & RTMEMMALLOC)
if (g_realloc_func != 0) {
void *newMemBlk = g_realloc_func (pMemLink->pMemBlk, nbytes_);
if (newMemBlk == 0)
return 0;
pMemLink->pMemBlk = newMemBlk;
}
else {
/* use malloc/memcpy/free sequence instead of realloc */
ASN1OCTET* newBuf;
int oldSize = *(int*)(((char*)pMemLink) + sizeof (OSMemLink));

if (oldSize == -1) return 0;
newBuf = (ASN1OCTET*)g_malloc_func (nbytes_);
if (newBuf == 0)
return 0;
memcpy (newBuf, pMemLink->pMemBlk, ASN1MIN (oldSize, nbytes_));
free (pMemLink->pMemBlk);
pMemLink->pMemBlk = newBuf;
}
else
return 0;
*(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = nbytes_;
return pMemLink->pMemBlk;
}
pPrevMemLink = pMemLink;
}

/* Round number of bytes to nearest 8-byte boundary */

nbytes = ((unsigned)(nbytes_ + 7)) & (~7);
nunits = nbytes >> 3;

pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);

RTMEMDIAG3 ("memHeapRealloc: mem_p = 0x%x, old size = %d,", mem_p,
pElem_nunits (pElem) * 8u);
RTMEMDIAG2 (" new nbytes = %d/n", nbytes);

if ((unsigned)pElem_nunits (pElem) == nunits)
return mem_p;

pMemBlk = GET_MEMBLK (pElem);

CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK(pMemHeap, pMemBlk);

if ((unsigned)pElem_nunits (pElem) < nunits) { /* expanding */

if (nunits - pElem_nunits (pElem) <= (unsigned)pMemBlk->nunits) {

/* Try to expand the existing element in the existing block */

if (ISLAST (pElem)) { /* if the last element in the block */

/* if the free space in the block is enough */

if ((int)(nunits - pElem_nunits (pElem)) <=
(int)(pMemBlk->nunits - pMemBlk->free_x))
{
pMemBlk->free_x += nunits - pElem_nunits (pElem);
pElem_nunits (pElem) = (ASN1USINT)nunits;

RTMEMDIAG1 ("memHeapRealloc: "
"memory element is expanded./n");

FILLNEWMEM (&pMemBlk->data [(pMemBlk->free_x -
(nunits - pElem_nunits (pElem))) * 8u],
(nunits - pElem_nunits (pElem)) * 8u);

TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);

return (mem_p);
}
}
else {
OSMemElemDescr* pNextElem, *pFreeElem;
unsigned sumSize = pElem_nunits (pElem), freeMem = 0;

RTMEMDIAG1 ("memHeapRealloc: look for free element after "
"current block./n");

/* look for free element after pElem */

pNextElem = GETNEXT (pElem);
if (ISFREE (pNextElem)) {
/* +1 'cos sizeof (OSMemElemDescr) == 1 unit */
sumSize += pElem_nunits (pNextElem) + 1;
freeMem++;
}

if (sumSize >= nunits) {

RTMEMDIAG1 ("memHeapRealloc: reuse free element./n");

if (ISFREE (pNextElem)) {
pFreeElem = GET_FREE_ELEM (pMemBlk);
if (pFreeElem == pNextElem) {
FORCE_SET_FREE_ELEM (pMemBlk, GET_NEXT_FREE (pNextElem));
}
else if (pFreeElem < pElem) {

/* look for previous free elem to correct nextFreeOff */

for (; pFreeElem != 0 && pFreeElem < pNextElem;) {
OSMemElemDescr* pNextFreeElem =
GET_NEXT_FREE (pFreeElem);
if (pNextFreeElem == pNextElem) {
if (pElem_nextFreeOff (pNextElem) != 0)
pElem_nextFreeOff (pFreeElem) = QOFFSETOF
(GET_NEXT_FREE (pNextElem), pFreeElem);
else
pElem_nextFreeOff (pFreeElem) = 0;
CHECKMEMELEM (pMemBlk, pFreeElem);
break;
}
pFreeElem = pNextFreeElem;
}
}
}

/* reuse empty elements after the pElem */

pMemBlk->freeMem += freeMem;

if (sumSize - nunits > 1) {
OSMemElemDescr* pNewElem;

/* if sumSize is too large, then create new empty element */

pNewElem = (OSMemElemDescr*)
(pElem_data (pElem) + nbytes);
pElem_nunits (pNewElem) = (ASN1USINT)(sumSize - nunits - 1);

initNewFreeElement (pMemBlk, pNewElem, pElem);

pMemBlk->freeMem--; /* sizeof (OSMemElemDescr) == 1 unit */
pMemBlk->freeMem -= (nunits - pElem_nunits (pElem));
pElem_nunits (pElem) = (ASN1USINT)nunits;
}
else {
pMemBlk->freeMem -= (sumSize - pElem_nunits (pElem));
pElem_nunits (pElem) = (ASN1USINT)sumSize;

/* modify the prevOff of the next elem */

pNextElem = GETNEXT (pElem);
if (pNextElem != 0)
pElem_prevOff (pNextElem) = QOFFSETOF (pNextElem, pElem);
}

TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMELEM (pMemBlk, (!ISLAST (pElem)) ? GETNEXT (pElem) : 0);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
return (mem_p);
}
}
}

/* If not successful, allocate a new element and move the data into it */

RTMEMDIAG1 ("memHeapRealloc: allocate new memory.../n");

CHECKMEMHEAP (pMemHeap);

newMem_p = memHeapAlloc (ppvMemHeap, nbytes);

if (newMem_p == 0)
return 0;

/* if the old memory block is marked as saved then mark the new block
as saved as well. */

if (ISSAVED (pElem))
memHeapMarkSaved (ppvMemHeap, newMem_p, TRUE);

CHECKMEMHEAP (pMemHeap);

memcpy (newMem_p, mem_p, (((ASN1UINT)pElem_nunits (pElem)) * 8u));

/* free old element */

RTMEMDIAG1 ("memHeapRealloc: free old pointer.../n");

memHeapFreePtr (ppvMemHeap, mem_p);

CHECKMEMHEAP (pMemHeap);

return (newMem_p);
}
else { /* shrinking */
RTMEMDIAG1 ("memHeapRealloc: shrinking .../n");

/* just free the pointer, if nbytes == 0 */

if (nbytes == 0) {
RTMEMDIAG1 ("memHeapRealloc: free pointer.../n");
memHeapFreePtr (ppvMemHeap, mem_p);
return (NULL);
}

/* do not shrink, if size diff is too small */

/* sizeof (OSMemElemDescr) == 1 unit */
if (pElem_nunits (pElem) - nunits > 1) {

/* if it is the last element in the block, then just change the size
and free_x. */

if (ISLAST (pElem)) {
pMemBlk->free_x -= (pElem_nunits (pElem) - nunits);

FILLFREEMEM (&pMemBlk->data [pMemBlk->free_x * 8u],
(pElem_nunits (pElem) - nunits) * 8u);
}
else {
OSMemElemDescr* pNewElem;

/* create new free element on the freed place */

pNewElem = (OSMemElemDescr*) (pElem_data (pElem) + nbytes);

/* sizeof (OSMemElemDescr) == 1 unit */
pElem_nunits (pNewElem) = (ASN1USINT)(pElem_nunits (pElem) - nunits - 1);

initNewFreeElement (pMemBlk, pNewElem, pElem);

pMemBlk->freeMem += (pElem_nunits (pElem) - nunits) - 1;
}
pElem_nunits (pElem) = (ASN1USINT)nunits;

TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMELEM (pMemBlk, (!ISLAST (pElem)) ? GETNEXT (pElem) : pElem);
CHECKMEMBLOCK (pMemHeap, pMemBlk);
}
return (mem_p);
}
}

/* Clears heap memory (frees all memory, reset all heap's variables) */
void memHeapFreeAll (void** ppvMemHeap)
{
OSMemHeap* pMemHeap;
OSMemLink* pMemLink;
OSMemLink* pMemLink2;

if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
pMemHeap = *(OSMemHeap**)ppvMemHeap;

pMemLink = pMemHeap->phead;
RTMEMDIAG2 ("memHeapFreeAll: pMemHeap = 0x%x/n", pMemHeap);

TRACEFREE (pMemHeap, "memHeapFreeAll/n/n");
CHECKMEMHEAP (pMemHeap);

/* Release any dynamic memory blocks that may have been allocated */

while (pMemLink) {
pMemLink2 = pMemLink;
pMemLink = pMemLink2->pnext;

RTMEMDIAG3 ("memHeapFreeAll: pMemLink2 = 0x%x, pMemLink = 0x%x/n",
pMemLink2, pMemLink);

#ifdef _MEMDEBUG
if (pMemLink2->blockType & RTMEMSTD) {
OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink2->pMemBlk;
FILLFREEMEM (pMemBlk->data, (pMemBlk->nunits * 8u));
FILLFREEMEM (pMemBlk, sizeof (*pMemBlk));
}
#endif
if (!(pMemLink2->blockType & RTMEMSAVED)) {
OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink2->pMemBlk;

/* unlink block first */

if(pMemLink2->pnext != 0) {
pMemLink2->pnext->pprev = pMemLink2->pprev;
}
if(pMemLink2->pprev != 0) {
pMemLink2->pprev->pnext = pMemLink2->pnext;
}
else { /* head */
pMemHeap->phead = pMemLink2->pnext;
}

/* correct heap's variables */

pMemHeap->usedUnits -= pMemBlk->nunits;

if (pMemBlk->free_x == 0)
pMemHeap->freeBlocks --;
else
pMemHeap->usedBlocks --;

/* free link and block */

if (((pMemLink2->blockType & RTMEMSTD) ||
(pMemLink2->blockType & RTMEMMALLOC)) &&
!(pMemLink2->blockType & RTMEMLINK))
g_free_func (pMemLink2->pMemBlk);
g_free_func (pMemLink2);
}
}
}

/* increments internal refCnt. use memHeapRelease to decrement and release */
void memHeapAddRef (void** ppvMemHeap)
{
OSMemHeap* pMemHeap;

if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
pMemHeap = *(OSMemHeap**)ppvMemHeap;
pMemHeap->refCnt++;
}

/* Frees all memory and heap structure as well (if was allocated) */
void memHeapRelease (void** ppvMemHeap)
{
OSMemHeap** ppMemHeap = (OSMemHeap**)ppvMemHeap;

if (ppMemHeap != 0 && *ppMemHeap != 0 && --(*ppMemHeap)->refCnt == 0) {
OSMemLink* pMemLink, *pMemLink2;

memHeapFreeAll (ppvMemHeap);

/* if there are RTMEMSAVED blocks - release memory for links only */

pMemLink = (*ppMemHeap)->phead;
while (pMemLink) {
pMemLink2 = pMemLink;
pMemLink = pMemLink2->pnext;

free (pMemLink2);
}

if ((*ppMemHeap)->flags & RT_MH_FREEHEAPDESC)
free (*ppMemHeap);

*ppMemHeap = 0;
}
}

/* This function is used for marking memory block as "saved". It means
* that the memory block containing the specified memory pointer won't be
* freed after calls to memHeapFreeAll/memHeapReset. User is responsible
* for freeing the marked memory block by call to memFreeBlock */

void* memHeapMarkSaved (void** ppvMemHeap, const void* mem_p,
ASN1BOOL saved)
{
OSMemHeap* pMemHeap;
OSMemLink* pMemLink;
ASN1UINT nsaved = 1;

RTMEMDIAG2 ("memHeapMarkSaved: for mem_p = 0x%x/n", mem_p);

if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0)
return 0;

pMemHeap = *(OSMemHeap**)ppvMemHeap;
pMemLink = pMemHeap->phead;

/* look for chain of RAW blocks first */

for (; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
if ((pMemLink->blockType & RTMEMRAW) &&
pMemLink->pMemBlk == mem_p)
{
break;
}
}
if (pMemLink == 0) {
OSMemElemDescr* pElem;
OSMemBlk* pMemBlk;

/* gain the MemLink from pointer */

pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);

if (ISFREE (pElem)) { /* already freed! */
RTMEMDIAG2 ("memHeapMarkSaved: the element 0x%x is "
"already free!/n", pElem);
return 0;
}

if ((ISSAVED (pElem) && !saved) || (!ISSAVED (pElem) && saved)) {

pMemBlk = GET_MEMBLK (pElem);

CHECKMEMELEM (pMemBlk, pElem);
CHECKMEMBLOCK(pMemHeap, pMemBlk);

pMemLink = pMemBlk->plink;

if (saved)
SET_SAVED (pMemBlk, pElem);
else
CLEAR_SAVED (pMemBlk, pElem);
nsaved = pMemBlk->nsaved;
}
else
return 0;
}
if (saved && nsaved > 0)
pMemLink->blockType |= RTMEMSAVED;
else if (nsaved == 0)
pMemLink->blockType &= (~RTMEMSAVED);
return pMemLink->pMemBlk;
}

/* This function will set the free index in all blocks to zero thereby */
/* allowing the blocks to be reused (ED, 3/17/2002).. */

void memHeapReset (void** ppvMemHeap)
{
OSMemHeap* pMemHeap;
OSMemLink *pMemLink;

if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
pMemHeap = *(OSMemHeap**)ppvMemHeap;

pMemLink = pMemHeap->phead;
TRACEFREE (pMemHeap, "memHeapReset/n/n");
while (pMemLink) {
if (!(pMemLink->blockType & RTMEMSAVED)) {
if (pMemLink->blockType & RTMEMSTD) {
OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;
if (pMemBlk->free_x != 0) {
pMemHeap->freeUnits += pMemBlk->nunits;
pMemHeap->freeBlocks ++;
}
pMemBlk->free_x = 0;
pMemBlk->freeElemOff = 0;
pMemBlk->lastElemOff = 0;
pMemBlk->freeMem = 0;
FILLFREEMEM (pMemBlk->data, pMemBlk->nunits * 8u);
}
else if (pMemLink->blockType & RTMEMRAW) {
/* if RAW block - free it */
memHeapFreePtr (ppvMemHeap, pMemLink->pMemBlk);
}
}
pMemLink = pMemLink->pnext;
}
}

/* add memory block to list */

static OSMemLink* memHeapAddBlock (OSMemLink** ppMemLink,
void* pMemBlk, int blockType)
{
OSMemLink* pMemLink;

/* if pMemBlk has RTMEMLINK flags it means that it is allocated
* cooperatively with OSMemLink, and we don't need to do additional
* allocations for it. Just use pointer's arithemtic. */

if (blockType & RTMEMLINK)
pMemLink = (OSMemLink*) (((ASN1OCTET*)pMemBlk) - sizeof (OSMemLink));
else {
pMemLink = (OSMemLink*) g_malloc_func (
sizeof(OSMemLink) + sizeof (int));
if (pMemLink == 0) return 0;
/* An extra integer is necessary to save a size of a RAW memory block
to perform rtMemRealloc through malloc/memcpy/free */
*(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = (int)-1;
}
if (pMemLink == NULL)
return NULL;
pMemLink->blockType = (ASN1OCTET)blockType;
pMemLink->pMemBlk = pMemBlk;
pMemLink->pprev = 0;
pMemLink->pnext = *ppMemLink;

if (*ppMemLink != 0) {
if ((*ppMemLink)->blockType & RTMEMRAW)
pMemLink->pnextRaw = *ppMemLink;
else {
pMemLink->pnextRaw = (*ppMemLink)->pnextRaw;
(*ppMemLink)->pnextRaw = 0;
}
}
else {
pMemLink->pnextRaw = 0;
}

*ppMemLink = pMemLink;
if (pMemLink->pnext != 0)
pMemLink->pnext->pprev = pMemLink;
((OSMemBlk*)pMemBlk)->plink = pMemLink; /*!AB */

RTMEMDIAG2 ("memHeapAddBlock: pMemLink = 0x%x/n", pMemLink);
RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pnext = 0x%x/n",
pMemLink->pnext);
RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pprev = 0x%x/n",
pMemLink->pprev);

return pMemLink;
}

int memHeapCheckPtr (void** ppvMemHeap, void* mem_p)
{
OSMemHeap* pMemHeap;
OSMemLink* pMemLink;

RTMEMDIAG2 ("memHeapCheckPtr: for mem_p = 0x%x/n", mem_p);

if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0)
return 0;
pMemHeap = *(OSMemHeap**)ppvMemHeap;

pMemLink = pMemHeap->phead;

for (; pMemLink != 0; pMemLink = pMemLink->pnext) {
if (pMemLink->blockType & RTMEMRAW) {

/* if RAW block, the pointer should be stored in pMemBlk */

if (pMemLink->pMemBlk == mem_p)
return 1;
}
else {
OSMemBlk* pMemBlk = (OSMemBlk*)pMemLink->pMemBlk;

/* Check, is the pointer inside this memory page */

if (mem_p > pMemLink->pMemBlk &&
mem_p < (void*)(((ASN1OCTET*)pMemLink->pMemBlk) + pMemBlk->nunits * 8u))
{
/* Check, is the pointer a correct element of the mem page */

OSMemElemDescr* pElem = (OSMemElemDescr*) pMemBlk->data;
for (; pElem != 0; pElem = GETNEXT (pElem)) {

void* curMem_p = (void*) pElem_data (pElem);
if (curMem_p == mem_p && !ISFREE (pElem))
return 1;
}
}
}
}
return 0;
}

void memHeapSetProperty (void** ppvMemHeap, ASN1UINT propId, void* pProp)
{
OSMemHeap* pMemHeap;

if (ppvMemHeap == 0)
return;

if (*ppvMemHeap == 0)
memHeapCreate (ppvMemHeap);

pMemHeap = *(OSMemHeap**)ppvMemHeap;
switch (propId) {
case OSRTMH_PROPID_DEFBLKSIZE:
pMemHeap->defBlkSize = *(ASN1UINT*)pProp;
break;
case OSRTMH_PROPID_SETFLAGS:
pMemHeap->flags |= ((*(ASN1UINT*)pProp) & (~RT_MH_INTERNALMASK));
break;
case OSRTMH_PROPID_CLEARFLAGS:
pMemHeap->flags &= ((~(*(ASN1UINT*)pProp)) | RT_MH_INTERNALMASK);
break;
}
}

int memHeapCreate (void** ppvMemHeap)
{
OSMemHeap* pMemHeap;
if (ppvMemHeap == 0) return ASN_E_INVPARAM;

pMemHeap = (OSMemHeap*) g_malloc_func (sizeof (OSMemHeap));
if (pMemHeap == NULL) return ASN_E_NOMEM;
memset (pMemHeap, 0, sizeof (OSMemHeap));
pMemHeap->defBlkSize = g_defBlkSize;
pMemHeap->refCnt = 1;
pMemHeap->flags = RT_MH_FREEHEAPDESC;
*ppvMemHeap = (void*)pMemHeap;
return ASN_OK;
}

以上就是全部程序了,用过,感觉很好,Very good。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值