Merged revisions 339245 via svnmerge from
[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    OSMemHeap* pMemHeap = *ppMemHeap;
1066
1067    if (ppMemHeap != 0 && *ppMemHeap != 0 && --(*ppMemHeap)->refCnt == 0) {
1068       OSMemLink* pMemLink, *pMemLink2;
1069
1070       memHeapFreeAll (ppvMemHeap);
1071
1072       /* if there are RTMEMSAVED blocks - release memory for links only */
1073
1074       pMemLink = (*ppMemHeap)->phead;
1075       while (pMemLink) {
1076          pMemLink2 = pMemLink;
1077          pMemLink  = pMemLink2->pnext;
1078
1079          free (pMemLink2);
1080       }
1081
1082       if ((*ppMemHeap)->flags & RT_MH_FREEHEAPDESC) {
1083          ast_mutex_destroy(&pMemHeap->pLock);
1084          free (*ppMemHeap);
1085       }
1086       *ppMemHeap = 0;
1087    }
1088 }
1089
1090 /* This function is used for marking memory block as "saved". It means
1091  * that the memory block containing the specified memory pointer won't be
1092  * freed after calls to memHeapFreeAll/memHeapReset. User is responsible 
1093  * for freeing the marked memory block by call to memFreeBlock */
1094
1095 void* memHeapMarkSaved (void** ppvMemHeap, const void* mem_p, 
1096                         ASN1BOOL saved) 
1097 {
1098    OSMemHeap* pMemHeap;
1099    OSMemLink* pMemLink;
1100    ASN1UINT nsaved = 1;
1101
1102    RTMEMDIAG2 ("memHeapMarkSaved: for mem_p = 0x%x\n", mem_p);
1103
1104    if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0) 
1105       return 0;
1106
1107    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1108
1109    ast_mutex_lock(&pMemHeap->pLock);
1110
1111    pMemLink = pMemHeap->phead;
1112
1113    /* look for chain of RAW blocks first */
1114
1115    for (; pMemLink != 0; pMemLink = pMemLink->pnextRaw) {
1116       if ((pMemLink->blockType & RTMEMRAW) &&
1117            pMemLink->pMemBlk == mem_p) 
1118       {
1119          break;
1120       }
1121    }
1122    if (pMemLink == 0) {
1123       OSMemElemDescr* pElem;
1124       OSMemBlk* pMemBlk;
1125
1126       /* gain the MemLink from pointer */
1127
1128       pElem = (OSMemElemDescr*) (((char*)mem_p) - sizeof_OSMemElemDescr);
1129
1130       if (ISFREE (pElem)) { /* already freed! */
1131          RTMEMDIAG2 ("memHeapMarkSaved: the element 0x%x is "
1132                          "already free!\n", pElem);
1133
1134          ast_mutex_unlock(&pMemHeap->pLock);
1135          return 0;   
1136       }
1137
1138       if ((ISSAVED (pElem) && !saved) || (!ISSAVED (pElem) && saved)) {
1139
1140          pMemBlk = GET_MEMBLK (pElem);
1141
1142          CHECKMEMELEM (pMemBlk, pElem);
1143          CHECKMEMBLOCK(pMemHeap, pMemBlk);
1144
1145          pMemLink = pMemBlk->plink;
1146
1147          if (saved) 
1148             SET_SAVED (pMemBlk, pElem);
1149          else
1150             CLEAR_SAVED (pMemBlk, pElem);
1151          nsaved = pMemBlk->nsaved;
1152       }
1153       else
1154          ast_mutex_unlock(&pMemHeap->pLock);
1155          return 0;
1156    }
1157    if (saved && nsaved > 0) 
1158       pMemLink->blockType |= RTMEMSAVED;
1159    else if (nsaved == 0)
1160       pMemLink->blockType &= (~RTMEMSAVED);
1161
1162    ast_mutex_unlock(&pMemHeap->pLock);
1163    return pMemLink->pMemBlk;
1164 }
1165
1166 /* This function will set the free index in all blocks to zero thereby  */
1167 /* allowing the blocks to be reused (ED, 3/17/2002)..                   */
1168
1169 void memHeapReset (void** ppvMemHeap)
1170 {
1171    OSMemHeap* pMemHeap;
1172    OSMemLink *pMemLink;
1173
1174    if (ppvMemHeap == 0 || *ppvMemHeap == 0) return;
1175    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1176
1177    ast_mutex_lock(&pMemHeap->pLock);
1178
1179    pMemLink = pMemHeap->phead;
1180    TRACEFREE (pMemHeap, "memHeapReset\n\n");
1181    while (pMemLink) {
1182       if (!(pMemLink->blockType & RTMEMSAVED)) {
1183          if (pMemLink->blockType & RTMEMSTD) {
1184             OSMemBlk* pMemBlk = (OSMemBlk*) pMemLink->pMemBlk;
1185             if (pMemBlk->free_x != 0) {
1186                pMemHeap->freeUnits += pMemBlk->nunits;
1187                pMemHeap->freeBlocks ++;
1188             }
1189             pMemBlk->free_x = 0;
1190             pMemBlk->freeElemOff = 0;
1191             pMemBlk->lastElemOff = 0;
1192             pMemBlk->freeMem = 0;
1193             FILLFREEMEM (pMemBlk->data, pMemBlk->nunits * 8u);
1194          }
1195          else if (pMemLink->blockType & RTMEMRAW) {
1196             /* if RAW block - free it */
1197             memHeapFreePtr (ppvMemHeap, pMemLink->pMemBlk);
1198          }
1199       }
1200       pMemLink = pMemLink->pnext;
1201    }
1202   ast_mutex_unlock(&pMemHeap->pLock);
1203 }
1204
1205 /* add memory block to list */
1206
1207 static OSMemLink* memHeapAddBlock (OSMemLink** ppMemLink, 
1208                                      void* pMemBlk, int blockType)
1209 {
1210    OSMemLink* pMemLink;
1211
1212    /* if pMemBlk has RTMEMLINK flags it means that it is allocated 
1213     * cooperatively with OSMemLink, and we don't need to do additional
1214     * allocations for it. Just use pointer's arithemtic. */
1215
1216    if (blockType & RTMEMLINK) 
1217       pMemLink = (OSMemLink*) (((ASN1OCTET*)pMemBlk) - sizeof (OSMemLink));
1218    else {
1219       pMemLink = (OSMemLink*) malloc (
1220          sizeof(OSMemLink) + sizeof (int));
1221       if (pMemLink == 0) return 0;
1222       /* An extra integer is necessary to save a size of a RAW memory block
1223          to perform rtMemRealloc through malloc/memcpy/free */
1224       *(int*)(((char*)pMemLink) + sizeof (OSMemLink)) = (int)-1;
1225    }
1226    if (pMemLink == NULL) 
1227       return NULL;
1228    pMemLink->blockType = (ASN1OCTET)blockType;
1229    pMemLink->pMemBlk = pMemBlk;
1230    pMemLink->pprev = 0;
1231    pMemLink->pnext = *ppMemLink;
1232
1233    if (*ppMemLink != 0) {
1234       if ((*ppMemLink)->blockType & RTMEMRAW)
1235          pMemLink->pnextRaw = *ppMemLink;
1236       else {
1237          pMemLink->pnextRaw = (*ppMemLink)->pnextRaw;
1238          (*ppMemLink)->pnextRaw = 0;
1239       }
1240    }
1241    else {
1242       pMemLink->pnextRaw = 0;
1243    }
1244
1245    *ppMemLink = pMemLink; 
1246    if (pMemLink->pnext != 0)
1247       pMemLink->pnext->pprev = pMemLink;
1248    ((OSMemBlk*)pMemBlk)->plink = pMemLink; /*!AB */
1249
1250    RTMEMDIAG2 ("memHeapAddBlock: pMemLink = 0x%x\n", pMemLink);
1251    RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pnext = 0x%x\n", 
1252                     pMemLink->pnext);
1253    RTMEMDIAG2 ("memHeapAddBlock: pMemLink->pprev = 0x%x\n", 
1254                     pMemLink->pprev);
1255
1256    return pMemLink;
1257 }
1258
1259 int memHeapCheckPtr (void** ppvMemHeap, void* mem_p)
1260 {
1261    OSMemHeap* pMemHeap;
1262    OSMemLink* pMemLink;
1263
1264    RTMEMDIAG2 ("memHeapCheckPtr: for mem_p = 0x%x\n", mem_p);
1265
1266    if (ppvMemHeap == 0 || *ppvMemHeap == 0 || mem_p == 0) 
1267       return 0;
1268    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1269
1270    ast_mutex_lock(&pMemHeap->pLock);
1271
1272    pMemLink = pMemHeap->phead;
1273
1274    for (; pMemLink != 0; pMemLink = pMemLink->pnext) {
1275       if (pMemLink->blockType & RTMEMRAW) {
1276          
1277          /* if RAW block, the pointer should be stored in pMemBlk */
1278
1279          if (pMemLink->pMemBlk == mem_p) {
1280             ast_mutex_unlock(&pMemHeap->pLock);
1281             return 1;
1282          }
1283       }
1284       else {
1285          OSMemBlk* pMemBlk = (OSMemBlk*)pMemLink->pMemBlk;
1286          
1287          /* Check, is the pointer inside this memory page */
1288
1289          if (mem_p > pMemLink->pMemBlk && 
1290              mem_p < (void*)(((ASN1OCTET*)pMemLink->pMemBlk) + pMemBlk->nunits * 8u))
1291          {
1292             /* Check, is the pointer a correct element of the mem page */
1293
1294             OSMemElemDescr* pElem = (OSMemElemDescr*) pMemBlk->data;
1295             for (; pElem != 0; pElem = GETNEXT (pElem)) {
1296               
1297                void* curMem_p = (void*) pElem_data (pElem);
1298                if (curMem_p == mem_p && !ISFREE (pElem)) {
1299                   ast_mutex_unlock(&pMemHeap->pLock);
1300                   return 1;
1301                }
1302             }
1303          }
1304       }
1305    }
1306
1307    ast_mutex_unlock(&pMemHeap->pLock);
1308    return 0;
1309 }
1310
1311 void memHeapSetProperty (void** ppvMemHeap, ASN1UINT propId, void* pProp)
1312 {
1313    OSMemHeap* pMemHeap;
1314
1315    if (ppvMemHeap == 0) 
1316       return;
1317
1318    if (*ppvMemHeap == 0)
1319       memHeapCreate (ppvMemHeap);
1320
1321    pMemHeap = *(OSMemHeap**)ppvMemHeap;
1322    ast_mutex_lock(&pMemHeap->pLock);
1323
1324    switch (propId) {
1325       case OSRTMH_PROPID_DEFBLKSIZE:
1326          pMemHeap->defBlkSize = *(ASN1UINT*)pProp;
1327          break;
1328       case OSRTMH_PROPID_SETFLAGS:
1329          pMemHeap->flags |= ((*(ASN1UINT*)pProp) & (~RT_MH_INTERNALMASK));
1330          break;
1331       case OSRTMH_PROPID_CLEARFLAGS:
1332          pMemHeap->flags &= ((~(*(ASN1UINT*)pProp)) | RT_MH_INTERNALMASK);
1333          break;
1334    }
1335    ast_mutex_unlock(&pMemHeap->pLock);
1336
1337
1338 int memHeapCreate (void** ppvMemHeap) 
1339 {
1340    OSMemHeap* pMemHeap;
1341    if (ppvMemHeap == 0) return ASN_E_INVPARAM;
1342
1343    pMemHeap = (OSMemHeap*) malloc (sizeof (OSMemHeap));
1344    if (pMemHeap == NULL) return ASN_E_NOMEM;
1345    memset (pMemHeap, 0, sizeof (OSMemHeap));
1346    pMemHeap->defBlkSize = g_defBlkSize;
1347    pMemHeap->refCnt = 1;
1348    pMemHeap->flags = RT_MH_FREEHEAPDESC;
1349    ast_mutex_init(&pMemHeap->pLock);
1350    *ppvMemHeap = (void*)pMemHeap;
1351    return ASN_OK;
1352 }
1353