0515ff9ac034035b8675bdcc65b91088f0346a41
[asterisk/asterisk.git] / addons / ooh323c / src / memheap.c
1 /*
2  * Copyright (C) 1997-2004 by Objective Systems, Inc.
3  *
4  * This software is furnished under an open source license and may be 
5  * used and copied only in accordance with the terms of this license. 
6  * The text of the license may generally be found in the root 
7  * directory of this installation in the LICENSE.txt file.  It 
8  * can also be viewed online at the following URL:
9  *
10  *   http://www.obj-sys.com/open/license.html
11  *
12  * Any redistributions of this file including modified versions must 
13  * maintain this copyright notice.
14  *
15  *****************************************************************************/
16 #include "asterisk.h"
17 #include "asterisk/lock.h"
18 #include <stdlib.h>
19 #include "memheap.h"
20
21 ASN1UINT      g_defBlkSize = XM_K_MEMBLKSIZ;
22
23 static OSMemLink* memHeapAddBlock (OSMemLink** ppMemLink, 
24                                    void* pMemBlk, int blockType);
25
26 typedef void OSMemElemDescr;
27
28
29 #define pElem_flags(pElem)       (*((ASN1OCTET*)pElem))
30 #define pElem_nunits(pElem)      (*((ASN1USINT*)(((ASN1OCTET*)pElem)+2)))
31 #define pElem_prevOff(pElem)     (*((ASN1USINT*)(((ASN1OCTET*)pElem)+4)))
32 #define pElem_nextFreeOff(pElem) (*((ASN1USINT*)(((ASN1OCTET*)pElem)+6)))
33 #define pElem_beginOff(pElem)    (*((ASN1USINT*)(((ASN1OCTET*)pElem)+6)))
34 #define sizeof_OSMemElemDescr    8
35 #define pElem_data(pElem)        (((ASN1OCTET*)pElem)+sizeof_OSMemElemDescr)
36
37 typedef struct MemBlk {
38    OSMemLink*      plink;
39    ASN1USINT       free_x;      /* index of free space at end of block */
40    ASN1USINT       freeMem;     /* size of free space before free_x    */
41    ASN1USINT       nunits;      /* size of data                        */
42    ASN1USINT       lastElemOff; /* last element offset in block        */
43    ASN1USINT       freeElemOff; /* first free element offset in block  */
44    ASN1USINT       nsaved;      /* num of saved elems in the block     */
45
46    ASN1USINT       spare[2];    /* forces alignment on 8-bytes boundary,
47                                    for 64-bit systems */
48    char            data[8];
49 } OSMemBlk;
50
51 /* Macros for operations with memory blocks */
52
53 #define QOFFSETOF(pElem, pPrevElem) \
54 ((ASN1USINT)(((unsigned)((char*)pElem - (char*)pPrevElem)) >> 3u))
55
56 #define OFFSETOF(pElem, pPrevElem) \
57 ((ASN1UINT)((char*)pElem - (char*)pPrevElem))
58
59 #define ISFREE(pElem)      (pElem_flags(pElem) & 1)
60 #define SET_FREE(pElem)    (pElem_flags(pElem) |= 1)
61 #define CLEAR_FREE(pElem)  (pElem_flags(pElem) &= (~1))
62
63 #define ISLAST(pElem)      (pElem_flags(pElem) & 2)
64 #define SET_LAST(pElem)    (pElem_flags(pElem) |= 2)
65 #define CLEAR_LAST(pElem)  (pElem_flags(pElem) &= (~2))
66
67 #define ISSAVED(pElem)      (pElem_flags(pElem) & 4)
68 #define SET_SAVED(pMemBlk,pElem)    do { \
69 (pElem_flags (pElem) |= 4); pMemBlk->nsaved++; } while (0)
70 #define CLEAR_SAVED(pMemBlk,pElem)  do { \
71 (pElem_flags (pElem) &= (~4)); pMemBlk->nsaved--; } while (0)
72
73 #define ISFIRST(pElem)    (int)(pElem_prevOff (pElem) == 0)
74
75 #define GETPREV(pElem) \
76 ((pElem_prevOff (pElem) == 0) ? 0 : \
77 ((OSMemElemDescr*) (((char*)pElem) - (pElem_prevOff (pElem) * 8u))))
78
79 #define GETNEXT(pElem) \
80 ((ISLAST (pElem)) ? 0 : \
81 ((OSMemElemDescr*)(((char*)pElem) + ((pElem_nunits (pElem) + 1) * 8u))))
82
83 #define GET_NEXT_FREE(pElem) \
84 ((pElem_nextFreeOff (pElem) == 0) ? 0 : \
85 ((OSMemElemDescr*) (((char*)pElem) + (pElem_nextFreeOff (pElem) * 8u))))
86
87 #define GET_MEMBLK(pElem) \
88 ((OSMemBlk*) (((char*)pElem) - (pElem_beginOff (pElem) * 8u) - \
89 sizeof (OSMemBlk) + sizeof ((OSMemBlk*)0)->data))
90
91 #define GET_LAST_ELEM(pMemBlk) \
92 ((pMemBlk->lastElemOff == 0) ? 0 : \
93 (OSMemElemDescr*)&pMemBlk->data[(pMemBlk->lastElemOff - 1) * 8u])
94
95 #define SET_LAST_ELEM(pMemBlk, pElem) \
96 pMemBlk->lastElemOff = (ASN1USINT)((pElem == 0) ? 0 : \
97 (SET_LAST (pElem), (QOFFSETOF (pElem, pMemBlk->data) + 1)))
98
99 #define GET_FREE_ELEM(pMemBlk) \
100 ((pMemBlk->freeElemOff == 0) ? 0 : \
101 (OSMemElemDescr*)&pMemBlk->data[(pMemBlk->freeElemOff - 1) * 8u])
102
103 #define FORCE_SET_FREE_ELEM(pMemBlk, pElem) do { \
104 if (pElem == 0) { pMemBlk->freeElemOff = 0; break; } \
105 SET_FREE (pElem); \
106 pMemBlk->freeElemOff = (ASN1USINT)(QOFFSETOF (pElem, pMemBlk->data) + 1); \
107 } while (0)
108
109 #define SET_FREE_ELEM(pMemBlk, pElem) setLastElem (pMemBlk, pElem)
110
111 /* Memory debugging macros */
112 #define RTMEMDIAG1(msg)       
113 #define RTMEMDIAG2(msg,a)  
114 #define RTMEMDIAG3(msg,a,b)
115 #define RTMEMDIAG4(msg,a,b,c)
116 #define FILLFREEMEM(mem,size)
117 #define FILLNEWMEM(mem,size) 
118
119 #define CHECKMEMELEM(memblk,elem)
120 #define CHECKMEMBLOCK(memheap,memblk)
121 #define CHECKMEMHEAP(memheap) 
122 #define TRACEMEMELEM(memblk, elem, name)
123 #define TRACEFREE(memlink,name)
124
125
126 static void setLastElem (OSMemBlk* pMemBlk, OSMemElemDescr* pElem) 
127 {
128    if (pElem == 0) { 
129       pMemBlk->freeElemOff = 0; 
130       return; 
131    }
132    else if (ISLAST (pElem)) 
133       return; 
134    else if (pMemBlk->freeElemOff > QOFFSETOF (pElem, pMemBlk->data) + 1) {
135       pElem_nextFreeOff (pElem) = QOFFSETOF (GET_FREE_ELEM (pMemBlk), pElem); 
136       FORCE_SET_FREE_ELEM (pMemBlk, pElem); 
137    } 
138    else if (pMemBlk->freeElemOff == 0) { 
139       pElem_nextFreeOff (pElem) = 0;          
140       FORCE_SET_FREE_ELEM (pMemBlk, pElem); 
141    } 
142    else { 
143       SET_FREE (pElem); 
144       pElem_nextFreeOff (pElem) = 0; 
145    }
146 }
147
148 void* memHeapAlloc (void** ppvMemHeap, int nbytes)
149 {
150    OSMemHeap* pMemHeap;
151    OSMemLink* pMemLink, **ppMemLink;
152    OSMemBlk*  pMemBlk = 0;
153    void* mem_p = NULL;
154    unsigned remUnits;
155    ASN1UINT nunits;
156
157    if (ppvMemHeap == 0)
158       return 0;
159
160    if (*ppvMemHeap == 0)
161       if (memHeapCreate (ppvMemHeap) != ASN_OK)
162          return 0;
163
164    /* Round number of bytes to nearest 8-byte boundary */
165
166    nunits = (((unsigned)(nbytes + 7)) >> 3);
167
168    pMemHeap = (OSMemHeap*) *ppvMemHeap;
169    ast_mutex_lock(&pMemHeap->pLock);
170    ppMemLink = &pMemHeap->phead;
171
172    /* if size is greater than 2**19, then allocate as RAW block */
173    
174    if (nunits > (1<<16) - 2) {
175       void *data;
176
177       /* allocate raw block */
178
179       data = malloc (nbytes);
180       if (data == NULL) {
181          return NULL;
182       }
183       pMemLink = memHeapAddBlock (ppMemLink, data, RTMEMMALLOC | RTMEMRAW);
184       if (pMemLink == 0) {
185          free (data);
186          return NULL;
187       }
188       /* save size of the RAW memory block behind the pMemLink */
189       *(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = nbytes;
190       ast_mutex_unlock(&pMemHeap->pLock);
191       return data;   
192    }
193    
194    RTMEMDIAG2 ("memHeapAlloc: adjusted nbytes = %d\n", nbytes);
195
196    /* Try to allocate a slot from an existing block on the list */
197
198    for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnext) {
199       if (pMemLink->blockType & RTMEMRAW) continue;
200       else pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;
201
202       remUnits = pMemBlk->nunits - pMemBlk->free_x;
203
204       if ((unsigned)(nunits + 1) <= remUnits) {
205          OSMemElemDescr* pElem = (OSMemElemDescr*)
206             &pMemBlk->data [((ASN1UINT)pMemBlk->free_x) * 8u];
207          OSMemElemDescr* pPrevElem;
208
209          RTMEMDIAG1 ("memHeapAlloc: found existing slot..\n");
210
211          /* if block is clean, set some vars in heap */
212          if (pMemBlk->free_x == 0) {
213             pMemHeap->freeUnits -= pMemBlk->nunits;
214             pMemHeap->freeBlocks--;
215          }
216
217          pElem_flags (pElem) = 0;
218          if (pMemBlk->lastElemOff != 0)
219             pElem_prevOff (pElem) = 
220                (ASN1USINT)(pMemBlk->free_x - pMemBlk->lastElemOff + 1);
221          else 
222             pElem_prevOff (pElem) = 0;
223          
224          pPrevElem = GET_LAST_ELEM (pMemBlk);
225          if (pPrevElem != 0)
226             CLEAR_LAST (pPrevElem);
227          
228          pElem_nunits (pElem) = (ASN1USINT)nunits; 
229          pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);
230          pMemBlk->lastElemOff = (ASN1USINT)(pMemBlk->free_x + 1);
231
232          mem_p = (void*) (pElem_data (pElem));
233          
234          /* sizeof (OSMemElemDescr) == 1 unit */
235          pMemBlk->free_x += nunits + 1; 
236          
237          SET_LAST_ELEM (pMemBlk, pElem);
238          
239          FILLNEWMEM (mem_p, nunits * 8u);
240          TRACEMEMELEM(pMemBlk, pElem, "Allocated");
241          CHECKMEMELEM (pMemBlk, pElem);
242          CHECKMEMBLOCK (pMemHeap, pMemBlk);
243          break;
244       }
245    }
246
247    /* If not successful, look for empty elements in existing blocks */
248
249    if (0 == mem_p) {
250       for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnext) {
251          if (pMemLink->blockType & RTMEMRAW) continue;
252          
253          pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;
254
255          if (nunits <= (ASN1UINT)pMemBlk->freeMem) {
256             OSMemElemDescr* pElem = GET_FREE_ELEM(pMemBlk), *pPrevFree = 0;
257
258             RTMEMDIAG2 
259            ("memHeapAlloc: try to reuse empty elems in pMemBlk = 0x%x...\n", 
260                 pMemBlk);
261
262             while (pElem != 0) {
263                if (ISFREE (pElem)) { 
264                   if (nunits <= (ASN1UINT)pElem_nunits (pElem)) {
265                      RTMEMDIAG3 
266                         ("memHeapAlloc: "
267                          "found an exisiting free element 0x%x, size %d\n", 
268                         pElem, (pElem_nunits (pElem) * 8u));
269                      
270                      if (pMemBlk->freeElemOff == 
271                          QOFFSETOF (pElem, pMemBlk->data) + 1) 
272                      {
273                         
274                         /* modify the pMemBlk->freeElemOff value if necsry */
275
276                         OSMemElemDescr* nextFree = GET_NEXT_FREE (pElem);
277                         FORCE_SET_FREE_ELEM (pMemBlk, nextFree); 
278                      }
279                      else if (pPrevFree != 0) {
280                         OSMemElemDescr* pNextFree = GET_NEXT_FREE (pElem);
281                         if (pNextFree != 0)
282                            pElem_nextFreeOff (pPrevFree) = QOFFSETOF (pNextFree, 
283                               pPrevFree);
284                         else
285                            pElem_nextFreeOff (pPrevFree) = 0;
286                      } 
287
288                      CLEAR_FREE (pElem);
289
290                      /* set beginOff value */
291
292                      pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);
293                      
294                      pMemBlk->freeMem -= pElem_nunits (pElem);
295
296                      CHECKMEMELEM (pMemBlk, pElem);
297                      CHECKMEMBLOCK (pMemHeap, pMemBlk);
298                      
299                      mem_p = memHeapRealloc 
300                         (ppvMemHeap, pElem_data (pElem), nunits * 8u);
301                      if (mem_p != 0) {
302                         FILLNEWMEM (mem_p, nunits * 8u);
303                         TRACEMEMELEM(pMemBlk, pElem, "Allocated");
304                      }
305                      break;
306                   }
307                }
308                pPrevFree = pElem;
309                pElem = GET_NEXT_FREE (pElem);
310             }
311             if (mem_p != 0) break;
312          }
313       }   
314    }
315
316    /* If not successful, malloc a new block and alloc from it */
317
318    if (!mem_p) {
319       ASN1UINT allocSize, dataUnits;
320       ASN1OCTET* pmem;
321       register ASN1UINT defBlkSize = pMemHeap->defBlkSize;
322
323       RTMEMDIAG1 ("memHeapAlloc: alloc block..\n");
324
325       allocSize = (ASN1UINT) ((((ASN1UINT)nunits) * 8u) + 
326          sizeof (OSMemBlk) + sizeof_OSMemElemDescr);
327       allocSize = (ASN1UINT) (allocSize < defBlkSize) ? defBlkSize : 
328          ((allocSize + defBlkSize - 1) / defBlkSize * defBlkSize);
329       dataUnits = (ASN1UINT)((allocSize - sizeof (OSMemBlk)) >> 3u);
330       if (dataUnits >= (1u<<16)) {
331          dataUnits = (ASN1UINT)((1u<<16) - 1);
332          allocSize = (ASN1UINT)
333             ((((ASN1UINT)dataUnits) * 8u) + sizeof (OSMemBlk));
334       }  
335
336       pmem = (ASN1OCTET*) malloc (allocSize + sizeof (OSMemLink));
337       if (0 != pmem) {
338          OSMemElemDescr* pElem;
339
340          pMemBlk = (OSMemBlk*) (pmem + sizeof (OSMemLink));
341          pElem = (OSMemElemDescr*)&pMemBlk->data[0];
342
343          mem_p = (void*) pElem_data (pElem);
344          pElem_nunits (pElem) = (ASN1USINT)nunits;
345          pElem_flags (pElem) = 0;
346          pElem_prevOff (pElem) = 0;
347          pElem_beginOff (pElem) = QOFFSETOF (pElem, pMemBlk->data);
348
349          /* sizeof (OSMemElemDescr) == 1 unit */
350          pMemBlk->free_x = (ASN1USINT)(nunits + 1); 
351
352          pMemBlk->freeMem = 0;
353          pMemBlk->nunits = (ASN1USINT)dataUnits;
354          SET_LAST_ELEM (pMemBlk, pElem);
355          pMemBlk->freeElemOff = 0;
356          pMemBlk->nsaved = 0;
357
358          if (memHeapAddBlock (ppMemLink, pMemBlk, RTMEMSTD | RTMEMLINK) == 0) 
359          {
360             free (pmem);
361             ast_mutex_unlock(&pMemHeap->pLock);
362             return NULL;
363          }
364
365          /* set vars in heap */
366          pMemHeap->usedUnits += dataUnits;
367          pMemHeap->usedBlocks++;
368
369          FILLNEWMEM (mem_p, nunits * 8u);
370          TRACEMEMELEM(pMemBlk, pElem, "Allocated");
371          CHECKMEMELEM (pMemBlk, pElem);
372          CHECKMEMBLOCK (pMemHeap, pMemBlk);
373       }
374       else  {
375          ast_mutex_unlock(&pMemHeap->pLock);
376          return NULL;
377       }
378    }
379    RTMEMDIAG2 ("memHeapAlloc: pMemBlk = 0x%x\n", pMemBlk);
380    RTMEMDIAG2 ("memHeapAlloc: pMemBlk->free_x = %d\n", pMemBlk->free_x);
381    RTMEMDIAG2 ("memHeapAlloc: pMemBlk->size = %d\n", 
382                     pMemBlk->nunits * 8u);
383    RTMEMDIAG2 ("memHeapAlloc: mem_p = 0x%x\n", mem_p);
384    RTMEMDIAG2 ("memHeapAlloc: sizeof (short) = %d\n", sizeof(short));
385
386    ast_mutex_unlock(&pMemHeap->pLock);
387    return (mem_p);
388 }
389
390 void* memHeapAllocZ (void** ppvMemHeap, int nbytes)
391 {
392    void* ptr = memHeapAlloc (ppvMemHeap, nbytes);
393    if (0 != ptr) memset (ptr, 0, nbytes);
394    return ptr;
395 }
396
397 void memHeapFreePtr (void** ppvMemHeap, void* mem_p) 
398 {
399    OSMemHeap* pMemHeap;
400    OSMemLink** ppMemLink;
401    OSMemElemDescr* pElem;
402    OSMemBlk* pMemBlk;
403    OSMemLink* pMemLink, *pPrevMemLink = 0;
404
405    RTMEMDIAG2 ("memHeapFreePtr: freeing mem_p = 0x%x\n", mem_p);
406
407    if (mem_p == 0 || ppvMemHeap == 0 || *ppvMemHeap == 0) return;
408
409    pMemHeap = *(OSMemHeap**)ppvMemHeap;
410
411    ast_mutex_lock(&pMemHeap->pLock);
412
413    ppMemLink = &pMemHeap->phead;
414
415    /* look for chain of RAW blocks first */
416
417    for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
418       if ((pMemLink->blockType & RTMEMRAW) &&
419            pMemLink->pMemBlk == mem_p) 
420       {
421          if(pMemLink->pnext != 0) {
422             pMemLink->pnext->pprev = pMemLink->pprev;
423          }
424          if(pMemLink->pprev != 0) {
425             pMemLink->pprev->pnext = pMemLink->pnext;
426          }
427          else { /* head */
428             *ppMemLink = pMemLink->pnext;
429          }
430          if (pPrevMemLink != 0)
431             pPrevMemLink->pnextRaw = pMemLink->pnextRaw;
432          else if (*ppMemLink != 0 && (*ppMemLink)->pnextRaw == 0 && 
433             *ppMemLink != pMemLink->pnextRaw)
434          {
435             (*ppMemLink)->pnextRaw = pMemLink->pnextRaw;
436          }
437          if ((pMemLink->blockType & RTMEMLINK) && 
438              (pMemLink->blockType & RTMEMMALLOC))
439          {
440             free (pMemLink);
441          }
442          else {
443             if (pMemLink->blockType & RTMEMMALLOC)
444                free (pMemLink->pMemBlk);
445             free (pMemLink);
446          }
447          ast_mutex_unlock(&pMemHeap->pLock);
448          return;
449       }
450       pPrevMemLink = pMemLink;
451    }
452
453    pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);
454    pMemBlk = GET_MEMBLK (pElem);
455
456    CHECKMEMELEM (pMemBlk, pElem);
457    CHECKMEMBLOCK(pMemHeap, pMemBlk);
458
459    if (ISFREE (pElem)) { /* already freed! */
460       RTMEMDIAG2 ("memHeapFreePtr: "
461                       "the element 0x%x is already freed!\n", pElem);
462       ast_mutex_unlock(&pMemHeap->pLock);
463       return;   
464    }
465
466    if (ISSAVED (pElem)) {
467       CLEAR_SAVED (pMemBlk, pElem);
468       if (pMemBlk->nsaved == 0)
469          pMemBlk->plink->blockType &= (~RTMEMSAVED);
470    }
471
472    TRACEMEMELEM(pMemBlk, pElem, "Freed");
473    CHECKMEMELEM (pMemBlk, pElem);
474    CHECKMEMBLOCK(pMemHeap, pMemBlk);
475
476    RTMEMDIAG2 ("memHeapFreePtr: pMemBlk = 0x%x\n", pMemBlk);
477    RTMEMDIAG2 ("memHeapFreePtr: pMemBlk->size = %d\n", 
478                     pMemBlk->nunits * 8u);
479
480    if (ISLAST (pElem)) { /* is it the last? */
481       OSMemElemDescr* pPrevElem = GETPREV (pElem);
482       
483       CHECKMEMELEM (pMemBlk, pPrevElem);
484
485       pMemBlk->free_x -= (pElem_nunits (pElem) + 1);
486
487       FILLFREEMEM (&pMemBlk->data [pMemBlk->free_x * 8u], 
488          (pElem_nunits (pElem) + 1) * 8u);
489
490       if (pPrevElem != 0 && ISFREE (pPrevElem)) {
491          OSMemElemDescr* pFreeElem;
492
493          pMemBlk->free_x -= (pElem_nunits (pPrevElem) + 1);
494          pMemBlk->freeMem -= pElem_nunits (pPrevElem);
495          SET_LAST_ELEM (pMemBlk, GETPREV (pPrevElem));
496          
497          /* wasn't it the last elem in block? */
498          if (pMemBlk->lastElemOff != 0) { 
499             
500             /* correct nextFreeOff for previous free element */
501
502             pFreeElem = GET_FREE_ELEM (pMemBlk);
503             if (pFreeElem == pPrevElem) {
504                pMemBlk->freeElemOff = 0; /* it was the last free elem */
505             }
506             else {
507                OSMemElemDescr* pNextFree = 0;
508                
509                while (pFreeElem < pPrevElem) {
510                   pNextFree = pFreeElem;
511                   pFreeElem = GET_NEXT_FREE (pFreeElem);
512                }
513                pElem_nextFreeOff (pNextFree) = 0;
514             }
515          }
516       }
517       else {
518          SET_LAST_ELEM (pMemBlk, pPrevElem);
519       }
520
521       RTMEMDIAG2 ("memHeapFreePtr: pMemBlk->free_x = %d\n", 
522                        pMemBlk->free_x);
523
524       /* The question is: do we really want to get rid of the   */
525       /* block or should we keep it around for reuse?           */
526       if (pMemBlk->lastElemOff == 0) { /* was it the last elem in block? */
527          
528          if ((pMemHeap->flags & RT_MH_DONTKEEPFREE) ||
529              (pMemHeap->keepFreeUnits > 0 && 
530               pMemHeap->freeUnits + pMemBlk->nunits > pMemHeap->keepFreeUnits))
531          {
532             ASN1OCTET blockType = pMemBlk->plink->blockType;
533
534             /* we may free the block */
535
536             pMemHeap->usedUnits -= pMemBlk->nunits;
537             pMemHeap->usedBlocks --;
538
539             if(pMemBlk->plink->pnext != 0) {
540                pMemBlk->plink->pnext->pprev = pMemBlk->plink->pprev;
541             }
542             if(pMemBlk->plink->pprev != 0) {
543                pMemBlk->plink->pprev->pnext = pMemBlk->plink->pnext;
544             }
545             else { /* head */
546                if (pMemBlk->plink->pnext != 0 && 
547                    !(pMemBlk->plink->pnext->blockType & RTMEMRAW))
548                {
549                   pMemBlk->plink->pnext->pnextRaw = (*ppMemLink)->pnextRaw;
550                }
551                *ppMemLink = pMemBlk->plink->pnext;
552             }
553             FILLFREEMEM (pMemBlk->plink, sizeof (*pMemBlk->plink));
554             FILLFREEMEM (pMemBlk->data, (pMemBlk->nunits * 8u));
555          
556             free (pMemBlk->plink);
557             
558             if (!(blockType & RTMEMLINK)) {
559                FILLFREEMEM (pMemBlk, sizeof (*pMemBlk));
560                free (pMemBlk);
561             }
562             RTMEMDIAG2 ("memHeapFreePtr: pMemBlk = 0x%x was freed\n", 
563                              pMemBlk);
564          }
565          else {
566             /* reset pMemBlk for re-usage */
567             pMemBlk->free_x = 0;
568             pMemBlk->freeElemOff = 0;
569             pMemBlk->lastElemOff = 0;
570             pMemBlk->freeMem = 0;
571             pMemBlk->nsaved = 0;
572             pMemHeap->freeUnits += pMemBlk->nunits;
573             pMemHeap->freeBlocks ++;
574          }
575       }
576       else {
577          SET_LAST (GET_LAST_ELEM (pMemBlk));
578          FILLFREEMEM (((char*) &pMemBlk->data[0]) + (pMemBlk->free_x * 8u), 
579                       (pMemBlk->nunits - pMemBlk->free_x) * 8u);
580          CHECKMEMBLOCK (pMemHeap, pMemBlk);
581       }
582    }
583    else { /* mark as free elem inside the block */
584       CHECKMEMBLOCK (pMemHeap, pMemBlk);
585
586       SET_FREE_ELEM(pMemBlk, pElem);
587
588       pMemBlk->freeMem += pElem_nunits (pElem);
589       RTMEMDIAG2 ("memHeapFreePtr: element 0x%x marked as free.\n", 
590                        pElem);
591
592       /* try to unite free blocks, if possible */
593       if (!ISFIRST (pElem)) {
594          if (ISFREE (GETPREV (pElem))) {
595             OSMemElemDescr* prevelem_p = GETPREV (pElem);
596          
597             /* +1 because the OSMemElemDescr has size ONE unit (8 bytes) */
598             pElem_nunits (prevelem_p) += pElem_nunits (pElem) + 1; 
599
600             pElem = prevelem_p;
601             pMemBlk->freeMem ++; /* sizeof (OSMemElemDescr) == 1 unit */
602          }
603          else {
604             /* look for nearest previous free block to correct nextFreeOff */
605          
606             OSMemElemDescr* prevelem_p = pElem;
607          
608             do {
609                prevelem_p = GETPREV (prevelem_p);
610             }
611             while (prevelem_p && !ISFREE (prevelem_p));
612
613             if (prevelem_p != 0) {
614                OSMemElemDescr* pNextFree =  GET_NEXT_FREE (prevelem_p);
615                if (pNextFree != 0) 
616                   pElem_nextFreeOff (pElem) = QOFFSETOF (pNextFree, pElem);
617                else
618                   pElem_nextFreeOff (pElem) = 0;
619                pElem_nextFreeOff (prevelem_p) = QOFFSETOF (pElem, prevelem_p);
620          
621                CHECKMEMELEM (pMemBlk, prevelem_p);
622             }
623          }
624       }
625       if (!ISLAST (pElem) && ISFREE (GETNEXT (pElem))) {
626          OSMemElemDescr* nextelem_p = GETNEXT (pElem);
627          
628          /* +1 because the OSMemElemDescr has size ONE unit (8 bytes) */
629          pElem_nunits (pElem) += pElem_nunits (nextelem_p) + 1; 
630
631          if (pElem_nextFreeOff (nextelem_p) == 0)
632             pElem_nextFreeOff (pElem) = 0;
633          else
634             pElem_nextFreeOff (pElem) = 
635                QOFFSETOF (GET_NEXT_FREE (nextelem_p), pElem);
636          pMemBlk->freeMem ++;
637       }
638
639       /* correct the prevOff field of next element */
640       if (!ISLAST (pElem)) {  
641          OSMemElemDescr* nextelem_p = GETNEXT (pElem);
642          pElem_prevOff (nextelem_p) = QOFFSETOF (nextelem_p, pElem);
643       }
644
645       CHECKMEMELEM (pMemBlk, pElem);
646       FILLFREEMEM (pElem_data (pElem), (pElem_nunits (pElem) * 8u));
647       CHECKMEMELEM (pMemBlk, pElem);
648       CHECKMEMBLOCK (pMemHeap, pMemBlk);
649    }
650   ast_mutex_unlock(&pMemHeap->pLock);
651
652
653 static void initNewFreeElement (OSMemBlk* pMemBlk, 
654    OSMemElemDescr* pNewElem, OSMemElemDescr* pElem) 
655 {
656    OSMemElemDescr *pNextElem, *pPrevElem = 0;
657
658    /* create new free element on the freed place */
659
660    pElem_flags (pNewElem) = 0;
661    SET_FREE (pNewElem);
662
663    pElem_prevOff (pNewElem) = QOFFSETOF (pNewElem, pElem);
664
665    if (pMemBlk->freeElemOff != 0 && 
666       pMemBlk->freeElemOff < QOFFSETOF (pElem, pMemBlk->data) + 1)
667    {
668       /* look for nearest previous free block to correct its nextFreeOff */
669       
670       pPrevElem = pElem;
671
672       do {
673          pPrevElem = GETPREV (pPrevElem);
674       }
675       while (pPrevElem && !ISFREE (pPrevElem));
676    }
677    if (pPrevElem != 0) { /* if it is not first free element... */
678
679       /* correct nextFreeOff for prev free element */
680       
681       pElem_nextFreeOff (pPrevElem) = QOFFSETOF (pNewElem, pPrevElem);
682    }
683    else {  /* if it is first free element in the block */
684       FORCE_SET_FREE_ELEM (pMemBlk, pNewElem);
685    }
686    
687    pNextElem = GETNEXT (pNewElem);
688    if (ISFREE (pNextElem)) {
689       
690       /* if the next elem is free, then unite them together */
691
692       pElem_nunits (pNewElem) += pElem_nunits (pNextElem) + 1;
693       if (pElem_nextFreeOff (pNextElem) != 0)
694          pElem_nextFreeOff (pNewElem) = QOFFSETOF (GET_NEXT_FREE (pNextElem), 
695             pNewElem);
696       else
697          pElem_nextFreeOff (pNewElem) = 0;
698       pMemBlk->freeMem++; /* +1 because space for MemElemDescr is freed now */
699       pNextElem = GETNEXT (pNewElem);
700    }
701    pElem_prevOff (pNextElem) = QOFFSETOF (pNextElem, pNewElem);
702
703    if (pMemBlk->freeElemOff != 0) {
704
705       /* look for the next nearest free elem */
706
707       pNextElem = GETNEXT (pNewElem);
708       while (pNextElem != 0 && !ISFREE (pNextElem))
709          pNextElem = GETNEXT (pNextElem);
710
711       /* set nextFreeOff for new element */
712    
713       if (pNextElem != 0)
714          pElem_nextFreeOff (pNewElem) = QOFFSETOF (pNextElem, pNewElem);
715       else
716          pElem_nextFreeOff (pNewElem) = 0;
717    }
718    else
719       pElem_nextFreeOff (pNewElem) = 0;
720
721 }
722
723 void* memHeapRealloc (void** ppvMemHeap, void* mem_p, int nbytes_)
724 {
725    OSMemHeap* pMemHeap;
726    OSMemLink** ppMemLink;
727    OSMemBlk* pMemBlk;
728    OSMemElemDescr* pElem;
729    OSMemLink* pMemLink, *pPrevMemLink = 0;
730    void *newMem_p;
731    unsigned nbytes, nunits;
732
733    /* if mem_p == NULL - do rtMemAlloc */
734
735    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return 0;
736
737    if (mem_p == 0) {
738       return memHeapAlloc (ppvMemHeap, nbytes_);
739    }
740
741    pMemHeap = *(OSMemHeap**)ppvMemHeap;
742    ppMemLink = &pMemHeap->phead;
743
744    /* look for chain of RAW blocks first */
745
746    for (pMemLink = *ppMemLink; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
747       if ((pMemLink->blockType & RTMEMRAW) &&
748            pMemLink->pMemBlk == mem_p) 
749       {
750          if (pMemLink->blockType & RTMEMMALLOC) {
751              void *newMemBlk = realloc (pMemLink->pMemBlk, nbytes_);
752              if (newMemBlk == 0) 
753                 return 0;
754              pMemLink->pMemBlk = newMemBlk;
755          }
756          else 
757             return 0;
758          *(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = nbytes_;
759          return pMemLink->pMemBlk;
760       }
761       pPrevMemLink = pMemLink;
762    }
763
764    /* Round number of bytes to nearest 8-byte boundary */
765
766    nbytes = ((unsigned)(nbytes_ + 7)) & (~7);
767    nunits = nbytes >> 3;
768
769    pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);
770
771    RTMEMDIAG3 ("memHeapRealloc: mem_p = 0x%x, old size = %d,",  mem_p, 
772                     pElem_nunits (pElem) * 8u);
773    RTMEMDIAG2 (" new nbytes = %d\n", nbytes);
774
775    if ((unsigned)pElem_nunits (pElem) == nunits)
776       return mem_p;
777
778    pMemBlk = GET_MEMBLK (pElem);
779
780    CHECKMEMELEM (pMemBlk, pElem);
781    CHECKMEMBLOCK(pMemHeap, pMemBlk);
782
783    if ((unsigned)pElem_nunits (pElem) < nunits) { /* expanding */
784    
785       if (nunits - pElem_nunits (pElem) <= (unsigned)pMemBlk->nunits) {
786
787          /* Try to expand the existing element in the existing block */
788
789          if (ISLAST (pElem)) { /* if the last element in the block */
790          
791             /* if the free space in the block is enough */
792          
793             if ((int)(nunits - pElem_nunits (pElem)) <= 
794                 (int)(pMemBlk->nunits - pMemBlk->free_x)) 
795             { 
796                pMemBlk->free_x += nunits - pElem_nunits (pElem);
797                pElem_nunits (pElem) = (ASN1USINT)nunits;
798
799                RTMEMDIAG1 ("memHeapRealloc: "
800                                "memory element is expanded.\n");
801                
802                FILLNEWMEM (&pMemBlk->data [(pMemBlk->free_x - 
803                   (nunits - pElem_nunits (pElem))) * 8u], 
804                   (nunits - pElem_nunits (pElem)) * 8u);
805                
806                TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
807                CHECKMEMELEM (pMemBlk, pElem);
808                CHECKMEMBLOCK (pMemHeap, pMemBlk);
809
810                return (mem_p);
811             } 
812          }
813          else {
814             OSMemElemDescr* pNextElem, *pFreeElem; 
815             unsigned sumSize = pElem_nunits (pElem), freeMem = 0;
816          
817             RTMEMDIAG1 ("memHeapRealloc: look for free element after "
818                "current block.\n");
819
820             /* look for free element after pElem */
821
822             pNextElem = GETNEXT (pElem);
823             if (ISFREE (pNextElem)) {
824                /* +1 'cos sizeof (OSMemElemDescr) == 1 unit */
825                sumSize += pElem_nunits (pNextElem) + 1; 
826                freeMem++;
827             }
828             
829             if (sumSize >= nunits) {
830
831                RTMEMDIAG1 ("memHeapRealloc: reuse free element.\n");
832
833                if (ISFREE (pNextElem)) {
834                   pFreeElem = GET_FREE_ELEM (pMemBlk);
835                   if (pFreeElem == pNextElem) {
836                      FORCE_SET_FREE_ELEM (pMemBlk, GET_NEXT_FREE (pNextElem));
837                   }
838                   else if (pFreeElem < pElem) {
839                      
840                      /* look for previous free elem to correct nextFreeOff */
841
842                      for (; pFreeElem != 0 && pFreeElem < pNextElem;) {
843                         OSMemElemDescr* pNextFreeElem = 
844                            GET_NEXT_FREE (pFreeElem);
845                         if (pNextFreeElem == pNextElem) {
846                            if (pElem_nextFreeOff (pNextElem) != 0)
847                               pElem_nextFreeOff (pFreeElem) = QOFFSETOF 
848                                  (GET_NEXT_FREE (pNextElem), pFreeElem);
849                            else
850                               pElem_nextFreeOff (pFreeElem) = 0;
851                            CHECKMEMELEM (pMemBlk, pFreeElem);
852                            break;
853                         }
854                         pFreeElem = pNextFreeElem;
855                      }
856                   }
857                }
858
859                /* reuse empty elements after the pElem */
860                
861                pMemBlk->freeMem += freeMem;
862      
863                if (sumSize - nunits > 1) {
864                   OSMemElemDescr* pNewElem;
865                
866                   /* if sumSize is too large, then create new empty element */
867
868                   pNewElem = (OSMemElemDescr*) 
869                      (pElem_data (pElem) + nbytes);
870                   pElem_nunits (pNewElem) = (ASN1USINT)(sumSize - nunits - 1);
871
872                   initNewFreeElement (pMemBlk, pNewElem, pElem);
873
874                   pMemBlk->freeMem--; /* sizeof (OSMemElemDescr) == 1 unit */
875                   pMemBlk->freeMem -= (nunits - pElem_nunits (pElem));
876                   pElem_nunits (pElem) = (ASN1USINT)nunits;
877                }
878                else {
879                   pMemBlk->freeMem -= (sumSize - pElem_nunits (pElem));
880                   pElem_nunits (pElem) = (ASN1USINT)sumSize;
881
882                   /* modify the prevOff of the next elem */
883
884                   pNextElem = GETNEXT (pElem);
885                   if (pNextElem != 0)
886                      pElem_prevOff (pNextElem) = QOFFSETOF (pNextElem, pElem);
887                }
888                
889                TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
890                CHECKMEMELEM (pMemBlk, pElem);
891                CHECKMEMELEM (pMemBlk, (!ISLAST (pElem)) ? GETNEXT (pElem) : 0);
892                CHECKMEMBLOCK (pMemHeap, pMemBlk);
893                return (mem_p);
894             }
895          }
896       }
897
898       /* If not successful, allocate a new element and move the data into it */
899
900       RTMEMDIAG1 ("memHeapRealloc: allocate new memory...\n");
901
902       CHECKMEMHEAP (pMemHeap);
903
904       newMem_p = memHeapAlloc (ppvMemHeap, nbytes);
905       
906       if (newMem_p == 0)
907          return 0;
908
909       /* if the old memory block is marked as saved then mark the new block
910          as saved as well. */
911
912       if (ISSAVED (pElem)) 
913          memHeapMarkSaved (ppvMemHeap, newMem_p, TRUE);
914
915       CHECKMEMHEAP (pMemHeap);
916
917       memcpy (newMem_p, mem_p, (((ASN1UINT)pElem_nunits (pElem)) * 8u));
918
919       /* free old element */
920
921       RTMEMDIAG1 ("memHeapRealloc: free old pointer...\n");
922
923       memHeapFreePtr (ppvMemHeap, mem_p);
924
925       CHECKMEMHEAP (pMemHeap);
926
927       return (newMem_p);
928    }
929    else { /* shrinking */
930       RTMEMDIAG1 ("memHeapRealloc: shrinking ...\n");
931       
932       /* just free the pointer, if nbytes == 0 */
933
934       if (nbytes == 0) {
935          RTMEMDIAG1 ("memHeapRealloc: free pointer...\n");
936          memHeapFreePtr (ppvMemHeap, mem_p);
937          return (NULL);
938       }
939
940       /* do not shrink, if size diff is too small */
941
942       /* sizeof (OSMemElemDescr) == 1 unit */
943       if (pElem_nunits (pElem) - nunits > 1) { 
944          
945          /* if it is the last element in the block, then just change the size 
946             and free_x. */
947
948          if (ISLAST (pElem)) {
949             pMemBlk->free_x -= (pElem_nunits (pElem) - nunits);
950
951             FILLFREEMEM (&pMemBlk->data [pMemBlk->free_x * 8u], 
952                (pElem_nunits (pElem) - nunits) * 8u);
953          }
954          else {
955             OSMemElemDescr* pNewElem;
956
957             /* create new free element on the freed place */
958
959             pNewElem = (OSMemElemDescr*) (pElem_data (pElem) + nbytes);
960
961             /* sizeof (OSMemElemDescr) == 1 unit */
962             pElem_nunits (pNewElem) = (ASN1USINT)(pElem_nunits (pElem) - nunits - 1); 
963             
964             initNewFreeElement (pMemBlk, pNewElem, pElem);
965             
966             pMemBlk->freeMem += (pElem_nunits (pElem) - nunits) - 1;
967          }
968          pElem_nunits (pElem) = (ASN1USINT)nunits;
969          
970          TRACEMEMELEM (pMemBlk, pElem, "Reallocated");
971          CHECKMEMELEM (pMemBlk, pElem);
972          CHECKMEMELEM (pMemBlk, (!ISLAST (pElem)) ? GETNEXT (pElem) : pElem);
973          CHECKMEMBLOCK (pMemHeap, pMemBlk);
974       }
975       return (mem_p);
976    }
977 }
978
979 /* Clears heap memory (frees all memory, reset all heap's variables) */
980 void memHeapFreeAll (void** ppvMemHeap)
981 {
982    OSMemHeap* pMemHeap;
983    OSMemLink* pMemLink;
984    OSMemLink* pMemLink2;
985
986    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
987    pMemHeap = *(OSMemHeap**)ppvMemHeap;
988
989    ast_mutex_lock(&pMemHeap->pLock);
990
991    pMemLink = pMemHeap->phead;
992    RTMEMDIAG2 ("memHeapFreeAll: pMemHeap = 0x%x\n", pMemHeap);
993
994    TRACEFREE (pMemHeap, "memHeapFreeAll\n\n");
995    CHECKMEMHEAP (pMemHeap);
996
997    /* Release any dynamic memory blocks that may have been allocated */
998
999    while (pMemLink) {
1000       pMemLink2 = pMemLink;
1001       pMemLink  = pMemLink2->pnext;
1002
1003       RTMEMDIAG3 ("memHeapFreeAll: pMemLink2 = 0x%x, pMemLink = 0x%x\n", 
1004                   pMemLink2, pMemLink);
1005       
1006 #ifdef _MEMDEBUG
1007       if (pMemLink2->blockType & RTMEMSTD) {
1008          OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink2->pMemBlk;
1009          FILLFREEMEM (pMemBlk->data, (pMemBlk->nunits * 8u));
1010          FILLFREEMEM (pMemBlk, sizeof (*pMemBlk));
1011       }
1012 #endif
1013       if (!(pMemLink2->blockType & RTMEMSAVED)) {
1014          OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink2->pMemBlk;
1015
1016          /* unlink block first */
1017
1018          if(pMemLink2->pnext != 0) {
1019             pMemLink2->pnext->pprev = pMemLink2->pprev;
1020          }
1021          if(pMemLink2->pprev != 0) {
1022             pMemLink2->pprev->pnext = pMemLink2->pnext;
1023          }
1024          else { /* head */
1025             pMemHeap->phead = pMemLink2->pnext;
1026          }
1027
1028          /* correct heap's variables */
1029
1030          pMemHeap->usedUnits -= pMemBlk->nunits;
1031
1032          if (pMemBlk->free_x == 0)
1033             pMemHeap->freeBlocks --;
1034          else
1035             pMemHeap->usedBlocks --;
1036
1037          /* free link and block */
1038
1039          if (((pMemLink2->blockType & RTMEMSTD) || 
1040               (pMemLink2->blockType & RTMEMMALLOC)) &&
1041               !(pMemLink2->blockType & RTMEMLINK)) 
1042             free (pMemLink2->pMemBlk);
1043          free (pMemLink2);
1044       }
1045    }
1046    ast_mutex_unlock(&pMemHeap->pLock);
1047 }
1048
1049 /* increments internal refCnt. use memHeapRelease to decrement and release */
1050 void memHeapAddRef (void** ppvMemHeap)
1051 {
1052    OSMemHeap* pMemHeap;
1053
1054    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
1055    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1056    ast_mutex_lock(&pMemHeap->pLock);
1057    pMemHeap->refCnt++;
1058    ast_mutex_unlock(&pMemHeap->pLock);
1059 }
1060
1061 /* Frees all memory and heap structure as well (if was allocated) */
1062 void memHeapRelease (void** ppvMemHeap)
1063 {
1064    OSMemHeap** ppMemHeap = (OSMemHeap**)ppvMemHeap;
1065
1066    if (ppMemHeap != 0 && *ppMemHeap != 0 && --(*ppMemHeap)->refCnt == 0) {
1067       OSMemLink* pMemLink, *pMemLink2;
1068
1069       memHeapFreeAll (ppvMemHeap);
1070
1071       /* if there are RTMEMSAVED blocks - release memory for links only */
1072
1073       pMemLink = (*ppMemHeap)->phead;
1074       while (pMemLink) {
1075          pMemLink2 = pMemLink;
1076          pMemLink  = pMemLink2->pnext;
1077
1078          free (pMemLink2);
1079       }
1080
1081       if ((*ppMemHeap)->flags & RT_MH_FREEHEAPDESC) {
1082          ast_mutex_destroy(&pMemHeap->pLock);
1083          free (*ppMemHeap);
1084       }
1085       *ppMemHeap = 0;
1086    }
1087 }
1088
1089 /* This function is used for marking memory block as "saved". It means
1090  * that the memory block containing the specified memory pointer won't be
1091  * freed after calls to memHeapFreeAll/memHeapReset. User is responsible 
1092  * for freeing the marked memory block by call to memFreeBlock */
1093
1094 void* memHeapMarkSaved (void** ppvMemHeap, const void* mem_p, 
1095                         ASN1BOOL saved) 
1096 {
1097    OSMemHeap* pMemHeap;
1098    OSMemLink* pMemLink;
1099    ASN1UINT nsaved = 1;
1100
1101    RTMEMDIAG2 ("memHeapMarkSaved: for mem_p = 0x%x\n", mem_p);
1102
1103    if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0) 
1104       return 0;
1105
1106    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1107
1108    ast_mutex_lock(&pMemHeap->pLock);
1109
1110    pMemLink = pMemHeap->phead;
1111
1112    /* look for chain of RAW blocks first */
1113
1114    for (; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
1115       if ((pMemLink->blockType & RTMEMRAW) &&
1116            pMemLink->pMemBlk == mem_p) 
1117       {
1118          break;
1119       }
1120    }
1121    if (pMemLink == 0) {
1122       OSMemElemDescr* pElem;
1123       OSMemBlk* pMemBlk;
1124
1125       /* gain the MemLink from pointer */
1126
1127       pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);
1128
1129       if (ISFREE (pElem)) { /* already freed! */
1130          RTMEMDIAG2 ("memHeapMarkSaved: the element 0x%x is "
1131                          "already free!\n", pElem);
1132
1133          ast_mutex_unlock(&pMemHeap->pLock);
1134          return 0;   
1135       }
1136
1137       if ((ISSAVED (pElem) && !saved) || (!ISSAVED (pElem) && saved)) {
1138
1139          pMemBlk = GET_MEMBLK (pElem);
1140
1141          CHECKMEMELEM (pMemBlk, pElem);
1142          CHECKMEMBLOCK(pMemHeap, pMemBlk);
1143
1144          pMemLink = pMemBlk->plink;
1145
1146          if (saved) 
1147             SET_SAVED (pMemBlk, pElem);
1148          else
1149             CLEAR_SAVED (pMemBlk, pElem);
1150          nsaved = pMemBlk->nsaved;
1151       }
1152       else
1153          ast_mutex_unlock(&pMemHeap->pLock);
1154          return 0;
1155    }
1156    if (saved && nsaved > 0) 
1157       pMemLink->blockType |= RTMEMSAVED;
1158    else if (nsaved == 0)
1159       pMemLink->blockType &= (~RTMEMSAVED);
1160
1161    ast_mutex_unlock(&pMemHeap->pLock);
1162    return pMemLink->pMemBlk;
1163 }
1164
1165 /* This function will set the free index in all blocks to zero thereby  */
1166 /* allowing the blocks to be reused (ED, 3/17/2002)..                   */
1167
1168 void memHeapReset (void** ppvMemHeap)
1169 {
1170    OSMemHeap* pMemHeap;
1171    OSMemLink *pMemLink;
1172
1173    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
1174    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1175
1176    ast_mutex_lock(&pMemHeap->pLock);
1177
1178    pMemLink = pMemHeap->phead;
1179    TRACEFREE (pMemHeap, "memHeapReset\n\n");
1180    while (pMemLink) {
1181       if (!(pMemLink->blockType & RTMEMSAVED)) {
1182          if (pMemLink->blockType & RTMEMSTD) {
1183             OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;
1184             if (pMemBlk->free_x != 0) {
1185                pMemHeap->freeUnits += pMemBlk->nunits;
1186                pMemHeap->freeBlocks ++;
1187             }
1188             pMemBlk->free_x = 0;
1189             pMemBlk->freeElemOff = 0;
1190             pMemBlk->lastElemOff = 0;
1191             pMemBlk->freeMem = 0;
1192             FILLFREEMEM (pMemBlk->data, pMemBlk->nunits * 8u);
1193          }
1194          else if (pMemLink->blockType & RTMEMRAW) {
1195             /* if RAW block - free it */
1196             memHeapFreePtr (ppvMemHeap, pMemLink->pMemBlk);
1197          }
1198       }
1199       pMemLink = pMemLink->pnext;
1200    }
1201   ast_mutex_unlock(&pMemHeap->pLock);
1202 }
1203
1204 /* add memory block to list */
1205
1206 static OSMemLink* memHeapAddBlock (OSMemLink** ppMemLink, 
1207                                      void* pMemBlk, int blockType)
1208 {
1209    OSMemLink* pMemLink;
1210
1211    /* if pMemBlk has RTMEMLINK flags it means that it is allocated 
1212     * cooperatively with OSMemLink, and we don't need to do additional
1213     * allocations for it. Just use pointer's arithemtic. */
1214
1215    if (blockType & RTMEMLINK) 
1216       pMemLink = (OSMemLink*) (((ASN1OCTET*)pMemBlk) - sizeof (OSMemLink));
1217    else {
1218       pMemLink = (OSMemLink*) malloc (
1219          sizeof(OSMemLink) + sizeof (int));
1220       if (pMemLink == 0) return 0;
1221       /* An extra integer is necessary to save a size of a RAW memory block
1222          to perform rtMemRealloc through malloc/memcpy/free */
1223       *(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = (int)-1;
1224    }
1225    if (pMemLink == NULL) 
1226       return NULL;
1227    pMemLink->blockType = (ASN1OCTET)blockType;
1228    pMemLink->pMemBlk = pMemBlk;
1229    pMemLink->pprev = 0;
1230    pMemLink->pnext = *ppMemLink;
1231
1232    if (*ppMemLink != 0) {
1233       if ((*ppMemLink)->blockType & RTMEMRAW)
1234          pMemLink->pnextRaw = *ppMemLink;
1235       else {
1236          pMemLink->pnextRaw = (*ppMemLink)->pnextRaw;
1237          (*ppMemLink)->pnextRaw = 0;
1238       }
1239    }
1240    else {
1241       pMemLink->pnextRaw = 0;
1242    }
1243
1244    *ppMemLink = pMemLink; 
1245    if (pMemLink->pnext != 0)
1246       pMemLink->pnext->pprev = pMemLink;
1247    ((OSMemBlk*)pMemBlk)->plink = pMemLink; /*!AB */
1248
1249    RTMEMDIAG2 ("memHeapAddBlock: pMemLink = 0x%x\n", pMemLink);
1250    RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pnext = 0x%x\n", 
1251                     pMemLink->pnext);
1252    RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pprev = 0x%x\n", 
1253                     pMemLink->pprev);
1254
1255    return pMemLink;
1256 }
1257
1258 int memHeapCheckPtr (void** ppvMemHeap, void* mem_p)
1259 {
1260    OSMemHeap* pMemHeap;
1261    OSMemLink* pMemLink;
1262
1263    RTMEMDIAG2 ("memHeapCheckPtr: for mem_p = 0x%x\n", mem_p);
1264
1265    if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0) 
1266       return 0;
1267    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1268
1269    ast_mutex_lock(&pMemHeap->pLock);
1270
1271    pMemLink = pMemHeap->phead;
1272
1273    for (; pMemLink != 0; pMemLink = pMemLink->pnext) {
1274       if (pMemLink->blockType & RTMEMRAW) {
1275          
1276          /* if RAW block, the pointer should be stored in pMemBlk */
1277
1278          if (pMemLink->pMemBlk == mem_p) {
1279             ast_mutex_unlock(&pMemHeap->pLock);
1280             return 1;
1281          }
1282       }
1283       else {
1284          OSMemBlk* pMemBlk = (OSMemBlk*)pMemLink->pMemBlk;
1285          
1286          /* Check, is the pointer inside this memory page */
1287
1288          if (mem_p > pMemLink->pMemBlk && 
1289              mem_p < (void*)(((ASN1OCTET*)pMemLink->pMemBlk) + pMemBlk->nunits * 8u))
1290          {
1291             /* Check, is the pointer a correct element of the mem page */
1292
1293             OSMemElemDescr* pElem = (OSMemElemDescr*) pMemBlk->data;
1294             for (; pElem != 0; pElem = GETNEXT (pElem)) {
1295               
1296                void* curMem_p = (void*) pElem_data (pElem);
1297                if (curMem_p == mem_p && !ISFREE (pElem)) {
1298                   ast_mutex_unlock(&pMemHeap->pLock);
1299                   return 1;
1300                }
1301             }
1302          }
1303       }
1304    }
1305
1306    ast_mutex_unlock(&pMemHeap->pLock);
1307    return 0;
1308 }
1309
1310 void memHeapSetProperty (void** ppvMemHeap, ASN1UINT propId, void* pProp)
1311 {
1312    OSMemHeap* pMemHeap;
1313
1314    if (ppvMemHeap == 0) 
1315       return;
1316
1317    if (*ppvMemHeap == 0)
1318       memHeapCreate (ppvMemHeap);
1319
1320    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1321    ast_mutex_lock(&pMemHeap->pLock);
1322
1323    switch (propId) {
1324       case OSRTMH_PROPID_DEFBLKSIZE:
1325          pMemHeap->defBlkSize = *(ASN1UINT*)pProp;
1326          break;
1327       case OSRTMH_PROPID_SETFLAGS:
1328          pMemHeap->flags |= ((*(ASN1UINT*)pProp) & (~RT_MH_INTERNALMASK));
1329          break;
1330       case OSRTMH_PROPID_CLEARFLAGS:
1331          pMemHeap->flags &= ((~(*(ASN1UINT*)pProp)) | RT_MH_INTERNALMASK);
1332          break;
1333    }
1334    ast_mutex_unlock(&pMemHeap->pLock);
1335
1336
1337 int memHeapCreate (void** ppvMemHeap) 
1338 {
1339    OSMemHeap* pMemHeap;
1340    if (ppvMemHeap == 0) return ASN_E_INVPARAM;
1341
1342    pMemHeap = (OSMemHeap*) malloc (sizeof (OSMemHeap));
1343    if (pMemHeap == NULL) return ASN_E_NOMEM;
1344    memset (pMemHeap, 0, sizeof (OSMemHeap));
1345    pMemHeap->defBlkSize = g_defBlkSize;
1346    pMemHeap->refCnt = 1;
1347    pMemHeap->flags = RT_MH_FREEHEAPDESC;
1348    ast_mutex_init(&pMemHeap->pLock);
1349    *ppvMemHeap = (void*)pMemHeap;
1350    return ASN_OK;
1351 }
1352