mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Now that these files are in the tree, they should prefer the tree's local copy of all Asterisk headers over any that may be installed. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@254931 65c4cc65-6c06-0410-ace0-fbb531ad65f3
		
			
				
	
	
		
			1352 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1352 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 "asterisk.h"
 | |
| #include "asterisk/lock.h"
 | |
| #include <stdlib.h>
 | |
| #include "memheap.h"
 | |
| 
 | |
| ASN1UINT      g_defBlkSize = XM_K_MEMBLKSIZ;
 | |
| 
 | |
| 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;
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
|    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 = malloc (nbytes);
 | |
|       if (data == NULL) {
 | |
|          return NULL;
 | |
|       }
 | |
|       pMemLink = memHeapAddBlock (ppMemLink, data, RTMEMMALLOC | RTMEMRAW);
 | |
|       if (pMemLink == 0) {
 | |
|          free (data);
 | |
|          return NULL;
 | |
|       }
 | |
|       /* save size of the RAW memory block behind the pMemLink */
 | |
|       *(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = nbytes;
 | |
|       ast_mutex_unlock(&pMemHeap->pLock);
 | |
|       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*) malloc (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) 
 | |
|          {
 | |
|             free (pmem);
 | |
| 	    ast_mutex_unlock(&pMemHeap->pLock);
 | |
|             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  {
 | |
| 	 ast_mutex_unlock(&pMemHeap->pLock);
 | |
|          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));
 | |
| 
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
|    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;
 | |
| 
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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))
 | |
|          {
 | |
|             free (pMemLink);
 | |
|          }
 | |
|          else {
 | |
|             if (pMemLink->blockType & RTMEMMALLOC)
 | |
|                free (pMemLink->pMemBlk);
 | |
|             free (pMemLink);
 | |
|          }
 | |
| 	 ast_mutex_unlock(&pMemHeap->pLock);
 | |
|          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);
 | |
|       ast_mutex_unlock(&pMemHeap->pLock);
 | |
|       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));
 | |
|          
 | |
|             free (pMemBlk->plink);
 | |
|             
 | |
|             if (!(blockType & RTMEMLINK)) {
 | |
|                FILLFREEMEM (pMemBlk, sizeof (*pMemBlk));
 | |
|                free (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);
 | |
|    }
 | |
|   ast_mutex_unlock(&pMemHeap->pLock);
 | |
| } 
 | |
| 
 | |
| 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) {
 | |
|              void *newMemBlk = realloc (pMemLink->pMemBlk, nbytes_);
 | |
|              if (newMemBlk == 0) 
 | |
|                 return 0;
 | |
|              pMemLink->pMemBlk = newMemBlk;
 | |
| 	 }
 | |
|          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;
 | |
| 
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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)) 
 | |
|             free (pMemLink2->pMemBlk);
 | |
|          free (pMemLink2);
 | |
|       }
 | |
|    }
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
| }
 | |
| 
 | |
| /* increments internal refCnt. use memHeapRelease to decrement and release */
 | |
| void memHeapAddRef (void** ppvMemHeap)
 | |
| {
 | |
|    OSMemHeap* pMemHeap;
 | |
| 
 | |
|    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
 | |
|    pMemHeap = *(OSMemHeap**)ppvMemHeap;
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
|    pMemHeap->refCnt++;
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
| }
 | |
| 
 | |
| /* 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;
 | |
| 
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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);
 | |
| 
 | |
| 	 ast_mutex_unlock(&pMemHeap->pLock);
 | |
|          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
 | |
| 	 ast_mutex_unlock(&pMemHeap->pLock);
 | |
|          return 0;
 | |
|    }
 | |
|    if (saved && nsaved > 0) 
 | |
|       pMemLink->blockType |= RTMEMSAVED;
 | |
|    else if (nsaved == 0)
 | |
|       pMemLink->blockType &= (~RTMEMSAVED);
 | |
| 
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
|    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;
 | |
| 
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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;
 | |
|    }
 | |
|   ast_mutex_unlock(&pMemHeap->pLock);
 | |
| }
 | |
| 
 | |
| /* 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*) malloc (
 | |
|          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;
 | |
| 
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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) {
 | |
| 	    ast_mutex_unlock(&pMemHeap->pLock);
 | |
|             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)) {
 | |
| 		  ast_mutex_unlock(&pMemHeap->pLock);
 | |
|                   return 1;
 | |
| 	       }
 | |
|             }
 | |
|          }
 | |
|       }
 | |
|    }
 | |
| 
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
|    return 0;
 | |
| }
 | |
| 
 | |
| void memHeapSetProperty (void** ppvMemHeap, ASN1UINT propId, void* pProp)
 | |
| {
 | |
|    OSMemHeap* pMemHeap;
 | |
| 
 | |
|    if (ppvMemHeap == 0) 
 | |
|       return;
 | |
| 
 | |
|    if (*ppvMemHeap == 0)
 | |
|       memHeapCreate (ppvMemHeap);
 | |
| 
 | |
|    pMemHeap = *(OSMemHeap**)ppvMemHeap;
 | |
|    ast_mutex_lock(&pMemHeap->pLock);
 | |
| 
 | |
|    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;
 | |
|    }
 | |
|    ast_mutex_unlock(&pMemHeap->pLock);
 | |
| } 
 | |
| 
 | |
| int memHeapCreate (void** ppvMemHeap) 
 | |
| {
 | |
|    OSMemHeap* pMemHeap;
 | |
|    if (ppvMemHeap == 0) return ASN_E_INVPARAM;
 | |
| 
 | |
|    pMemHeap = (OSMemHeap*) malloc (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;
 | |
|    ast_mutex_init(&pMemHeap->pLock);
 | |
|    *ppvMemHeap = (void*)pMemHeap;
 | |
|    return ASN_OK;
 | |
| }
 | |
| 
 |