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