dect
/
asterisk
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
asterisk/addons/ooh323c/src/memheap.c

1332 lines
42 KiB
C

/*
* Copyright (C) 1997-2004 by Objective Systems, Inc.
*
* This software is furnished under an open source license and may be
* used and copied only in accordance with the terms of this license.
* The text of the license may generally be found in the root
* directory of this installation in the LICENSE.txt file. It
* can also be viewed online at the following URL:
*
* http://www.obj-sys.com/open/license.html
*
* 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)
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;
}