openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

mem_avl.c (23784B)


      1 
      2 /*
      3  * 
      4  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      5  * 
      6  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      7  *
      8  * Generic Memory Manager using AVL Tree
      9  *
     10  * NOTE: These routines are NOT thread-safe.  If multiple threads could
     11  * access an AVL tree, external locks must be used to mutually exclude
     12  * each call to the shr_avl routines, including shr_avl_traverse().
     13  */
     14 #include <shared/bsl.h>
     15 
     16 #include <sal/types.h>
     17 #include <shared/alloc.h>
     18 #include <sal/core/libc.h>
     19 #include <shared/mem_avl.h>
     20 #include <assert.h>
     21 
     22 #define MEM_AVL_DEBUG
     23 #ifdef MEM_AVL_DEBUG
     24 #include <soc/cm.h>
     25 #endif
     26 /*
     27  *
     28  *     The memory management scheme works as follows:
     29  *
     30  *     Structure:
     31  *         AVL Tree:
     32  *           Each node in the tree describes a free block of memory.
     33  *           Said node has the number of memory units contained in the block,
     34  *           as well as the starting address (within the block) of the
     35  *           block.
     36  *         Doubly Linked List:
     37  *           The nodes within the aforementioned tree have previous and next
     38  *           pointers to allow for a DLL.  This DLL is used to coalesce
     39  *           adjacent free blocks, reducing fragmentation, and allowing for
     40  *           larger blocks to be allocated.
     41  *
     42  *     Initialization:
     43  *           We start with a single node avl tree.  This is deemed the 'free'
     44  *           block tree.  The node has the entire memory to be managed and is
     45  *           the head of our doubly linked list.
     46  *
     47  *     Allocation:
     48  *           We execute a best fit search of the free tree.
     49  *           The node returned to us is removed from the tree.  If the node
     50  *           returned to us is larger than our need, we split off the
     51  *           unused portion and add said portion back into the tree.
     52  *           We mark the allocated portion used, insert the remainder
     53  *           into the DLL (the allocated node was already in the DLL).
     54  *           We then return the memory address to the user.
     55  *
     56  *     ReAlloc:
     57  *           If the realloc size is identical, we simply return the same
     58  *           address to the user.
     59  *           Otherwise, we free the associated block, (with possible
     60  *           coalescence), and allocate a fresh block.
     61  *           One item of note, this implementation of realloc does not
     62  *           copy the original contents of the memory to the new location.
     63  *
     64  *     Free:
     65  *           Find the node (within the DLL) associated with this block of
     66  *           memory.  If the previous block is free also, coalesce the two
     67  *           blocks into one.  If the next block is free, coalesce that block
     68  *           into this one.  Mark the memory as free in the DLL, and add it to
     69  *           the free tree.
     70  *
     71  * LANGUAGE:
     72  *
     73  *     C
     74  *
     75  * AUTHORS:
     76  *
     77  *     Travis B. Sawyer, Sean Campbell
     78  *
     79  * CREATION DATE:
     80  *
     81  *     21-June-2005
     82  *     Rewritten to use AVL free tree on:
     83  *     27-July-2005
     84  */
     85 
     86 /*
     87  * Internally used functions
     88  */
     89 static void shr_mem_avl_list_tree(shr_avl_entry_t *a, int m);
     90 static int _shr_mem_avl_remove(shr_mem_avl_t *mem_avl,
     91                                shr_mem_avl_entry_pt entry);
     92 static int _shr_mem_avl_compare(void *user_data,
     93                                 shr_avl_datum_t *a,
     94                                 shr_avl_datum_t *b);
     95 static int _shr_mem_avl_dll_insert(shr_mem_avl_t* mem_avl,
     96                                    shr_mem_avl_entry_pt entry);
     97 static int _shr_mem_avl_dll_remove(shr_mem_avl_t *mem_avl,
     98                                    shr_mem_avl_entry_pt entry);
     99 static shr_mem_avl_entry_pt _shr_mem_avl_dll_search(shr_mem_avl_t *mem_avl, 
    100                                                     unsigned int addr,
    101                                                     unsigned int loose);
    102 
    103 static void _shr_mem_avl_find_free_count(shr_avl_entry_t* entry,
    104                                         int size,
    105                                         int *count);
    106 
    107 int shr_mem_avl_create(shr_mem_avl_t **mem_avl_ptr,
    108                        int mem_size,
    109                        int mem_base,
    110                        int max_blocks)
    111 {
    112     int status = 0;
    113     shr_mem_avl_entry_t *entry;
    114     shr_mem_avl_t *mem_avl;
    115 
    116     mem_avl = sal_alloc(sizeof(shr_mem_avl_t), "mem_avl");
    117     if (mem_avl == NULL) {
    118         return -1;
    119     }
    120     
    121     sal_memset(mem_avl, 0, sizeof(*mem_avl));
    122 
    123     *mem_avl_ptr = mem_avl;
    124 
    125     /* create the AVL tree.
    126        Datum is shr_mem_avl_entry_s */
    127     status = shr_avl_create(&mem_avl->tree, NULL, 
    128                              sizeof(shr_mem_avl_entry_t), max_blocks);
    129     if (status != 0) {
    130         return status;
    131     }
    132 
    133     /* Initialize and create a single entry with the whole mem */
    134     entry = sal_alloc(sizeof(shr_mem_avl_entry_t), "mem_avl");
    135 
    136     if (entry == NULL) {
    137         return -1;
    138     }
    139 
    140     sal_memset(entry, 0, sizeof(*entry));
    141 
    142     /* Initialize doubly linked list (for block coalesence) */
    143     entry->size = mem_size;
    144     entry->addr = mem_base;
    145     entry->next = NULL;
    146     entry->prev = NULL;
    147     entry->self = entry;
    148 
    149     mem_avl->mem_list = entry;
    150 
    151     /* insert the entry into the avl tree */
    152     status = shr_avl_insert(mem_avl->tree, _shr_mem_avl_compare, 
    153                    (shr_avl_datum_t*)((mem_avl->mem_list)));
    154 
    155     return( status );
    156 }
    157 
    158 static int _shr_mem_avl_compare(void *user_data, shr_avl_datum_t *a, 
    159                                     shr_avl_datum_t *b)
    160 {
    161     int size_diff;
    162 
    163     COMPILER_REFERENCE(user_data);
    164 
    165     size_diff = (((shr_mem_avl_entry_pt)(a))->size - 
    166                  ((shr_mem_avl_entry_pt)(b))->size);
    167 
    168     if (!size_diff) {
    169         /* both entries are of same size...check the address. If both have
    170          * same address (which means its the same entry) return 0 else 1 
    171          */
    172         if (((shr_mem_avl_entry_pt)(a))->addr ==
    173               ((shr_mem_avl_entry_pt)(b))->addr) {
    174             return 0;
    175         }
    176         if (((shr_mem_avl_entry_pt)(a))->addr >
    177               ((shr_mem_avl_entry_pt)(b))->addr) {
    178             return 1;
    179         }
    180             return -1;
    181     }
    182 
    183     return size_diff;
    184 }
    185 int shr_mem_avl_destroy(shr_mem_avl_t *mem_avl)
    186 {
    187     int status, rv = 0;
    188     shr_mem_avl_entry_pt entry;
    189     shr_mem_avl_entry_pt next;
    190 
    191     /* destroy the avl tree. Frees the space for datum's also. */
    192     status = shr_avl_destroy(mem_avl->tree);
    193     if (status != 0) {
    194         rv = -1;
    195     }
    196     mem_avl->tree = NULL;
    197 
    198     /*
    199      * Now walk the dll and free each entry
    200      */
    201     entry = mem_avl->mem_list;
    202 
    203     while (NULL != entry) {
    204         next = entry->next;
    205         sal_free(entry);
    206         entry = next;
    207     }
    208     mem_avl->mem_list = NULL;
    209 
    210     return rv;
    211 }
    212 
    213 static int _shr_mem_avl_avl_search_compare(shr_avl_datum_t *a, 
    214                                           shr_avl_datum_t *b)
    215 {
    216     return (((shr_mem_avl_entry_pt)(a))->size - 
    217             ((shr_mem_avl_entry_pt)(b))->size);
    218 }
    219 
    220 /* performs bestfit search of the avl tree to find the free block */
    221 static shr_avl_datum_t* _shr_mem_avl_avl_search(shr_avl_t *tree, 
    222                                                 shr_avl_datum_t *datum)
    223 {
    224     int                 cmp_rv;
    225     shr_avl_datum_t     *result = NULL;
    226     shr_avl_t           sub_tree;
    227 
    228     if ((!tree) || (!tree->root)) {
    229         return NULL;
    230     }
    231 
    232     cmp_rv = _shr_mem_avl_avl_search_compare(&tree->root->datum, datum);
    233 
    234     if (cmp_rv > 0) {
    235         /* search left sub-tree */
    236         if (tree->root->left != NULL) {
    237             sub_tree.root = tree->root->left;
    238             result = _shr_mem_avl_avl_search(&sub_tree, datum);
    239             if (result != NULL) {
    240                 cmp_rv = _shr_mem_avl_avl_search_compare(result, datum);
    241                 if (cmp_rv < 0) {
    242                     result = &tree->root->datum;
    243                 }
    244             }
    245         } else {
    246             result = &tree->root->datum;
    247         }
    248     }
    249 
    250     if (cmp_rv == 0) {
    251         result = &tree->root->datum;
    252     }
    253 
    254     if (cmp_rv < 0) {
    255         /* search right sub-tree */
    256         if (tree->root->right != NULL) {
    257             sub_tree.root = tree->root->right;
    258             result = _shr_mem_avl_avl_search(&sub_tree, datum);
    259             if (result != NULL) {
    260                 cmp_rv = _shr_mem_avl_avl_search_compare(result, datum);
    261                 if (cmp_rv < 0) {
    262                     result = &tree->root->datum;
    263                 }
    264             }
    265         } else {
    266             result = &tree->root->datum;
    267         }
    268     }
    269 
    270     return result;
    271 }
    272 
    273 int shr_mem_avl_malloc(shr_mem_avl_t *mem_avl, int size, unsigned int *addr)
    274 {
    275     shr_mem_avl_entry_t entry;
    276     shr_mem_avl_entry_pt curr_entry;
    277     shr_mem_avl_entry_pt split_entry;
    278     void *pTmpVoid;
    279 #ifndef NDEBUG
    280     int nStatus;
    281 #endif /* !NDEBUG*/
    282     shr_avl_datum_t *pDatumSearch, *pDatum;
    283 
    284     assert(mem_avl != 0);
    285     assert(addr);
    286 
    287     if (0 == size) {
    288         /*
    289          * What does malloc do here?
    290          */
    291         return( -1 );
    292     }
    293 
    294     /*
    295      * Need to search the tree to find the best fit.
    296      */
    297     sal_memset(&entry, 0, sizeof(entry));
    298     entry.size = size;
    299     pDatumSearch = (shr_avl_datum_t *) &entry;
    300 
    301     pDatum = _shr_mem_avl_avl_search(mem_avl->tree, pDatumSearch);
    302     if (NULL == pDatum) {
    303         /* OOM */
    304         return( -1 );
    305     }
    306     curr_entry = ((shr_mem_avl_entry_pt)(pDatum))->self;
    307 
    308     if (size > curr_entry->size) {
    309         /* OOM */
    310         return( -1 );
    311     }
    312 
    313     /*
    314      * Remove the node from the free tree
    315      */
    316     /*
    317      * ENHANCEME: do something with the status from avl_remove
    318      */
    319 #ifndef NDEBUG
    320     nStatus = 
    321 #endif /* !NDEBUG*/
    322     _shr_mem_avl_remove(mem_avl, curr_entry);
    323 
    324     assert(nStatus >= 0);
    325 
    326     /*
    327      * We have a 'free' block of memory.  It may be larger than we need,
    328      * if it is, we need to split off the extra and put that back into
    329      * the free tree
    330      */
    331     if (size < curr_entry->size) {
    332         /*
    333          * The search returned a free block that is greater than
    334          * what we need.  We need to split off the unused lines,
    335          * and add that back to the free tree.
    336          */
    337         pTmpVoid = NULL;
    338         pTmpVoid = sal_alloc(sizeof(*split_entry), "mem_avl");
    339         if (NULL == pTmpVoid) {
    340             /* OOSM */
    341             return( -1 );
    342         }
    343 
    344         split_entry = (shr_mem_avl_entry_pt)pTmpVoid;
    345 
    346         sal_memset(split_entry, 0, sizeof(*split_entry));
    347         split_entry->size = curr_entry->size - size;
    348         split_entry->addr = curr_entry->addr + entry.size;
    349         split_entry->next = NULL;
    350         split_entry->prev = NULL;
    351         split_entry->self = split_entry;
    352 
    353         /*
    354          * Since we're splitting, we have to update the 'allocated' node's
    355          * size appropriately
    356          */
    357         curr_entry->size = size;
    358 
    359 
    360         /*
    361          * ENHANCEME: do something with the status from avl_insert
    362          */
    363 #ifndef NDEBUG
    364         nStatus = 
    365 #endif /*!NDEBUG*/
    366         shr_avl_insert(mem_avl->tree, _shr_mem_avl_compare, 
    367                                  (shr_avl_datum_t*)split_entry);
    368         assert(nStatus >= 0);
    369         _shr_mem_avl_dll_insert(mem_avl, split_entry);
    370     }
    371 
    372     /*
    373      * Now take care of the block we're interested in
    374      */
    375     *addr = curr_entry->addr;
    376     curr_entry->used = 1;
    377 
    378     return( 0 );
    379 }
    380 
    381 int shr_mem_avl_realloc(shr_mem_avl_t *mem_avl, int size, unsigned int addr)
    382 {
    383     shr_mem_avl_entry_pt curr_entry;
    384     shr_mem_avl_entry_pt split_entry;
    385     void *pTmpVoid;
    386 #ifndef NDEBUG
    387     int nStatus;
    388 #endif /* !NDEBUG*/
    389 
    390     assert(mem_avl != 0);
    391 
    392     if (0 == size) {
    393         /*
    394          * What does realloc do here?
    395          */
    396         return( -1 );
    397     }
    398 
    399     /* use loose search to find target block */
    400     curr_entry = _shr_mem_avl_dll_search(mem_avl, addr, 1);
    401     if (NULL == curr_entry) {
    402         /*
    403          * This is bad, we couldn't find a
    404          * block containing this address
    405          */
    406         return( -1 );
    407     }
    408 
    409     /* verify size and availability */
    410     if ( ((curr_entry->addr + curr_entry->size - 1) < (addr + size - 1)) ||
    411           (curr_entry->used) ) {
    412         return( -1 );
    413     }
    414 
    415     /*
    416      * Remove the node from the free tree
    417      */
    418     /*
    419      * ENHANCEME: do something with the status from avl_remove
    420      */
    421 #ifndef NDEBUG
    422     nStatus =
    423 #endif /* !NDEBUG*/
    424     _shr_mem_avl_remove(mem_avl, curr_entry);
    425     assert(nStatus >= 0);
    426 
    427     /*
    428      * We have a 'free' block of memory.  The starting address of this
    429      * block may not matched the target.  If not, split off the first
    430      * portian and place it back into the free tree
    431      */
    432     if (addr > curr_entry->addr) {
    433         /*
    434          * The search returned a free block that contains the
    435          * desired block.  The start address is not a match so we
    436          * need to split off the portion prior to the target
    437          * address and add it back to the free tree.
    438          */
    439         pTmpVoid = NULL;
    440         pTmpVoid = sal_alloc(sizeof(*split_entry), "mem_avl");
    441         if (NULL == pTmpVoid) {
    442             /* OOSM */
    443             return( -1 );
    444         }
    445 
    446         split_entry = (shr_mem_avl_entry_pt)pTmpVoid;
    447 
    448         sal_memset(split_entry, 0, sizeof(*split_entry));
    449         split_entry->size = addr - curr_entry->addr;
    450         split_entry->addr = curr_entry->addr;
    451         split_entry->next = NULL;
    452         split_entry->prev = NULL;
    453         split_entry->self = split_entry;
    454 
    455         /*
    456          * Since we're splitting, we have to update the 'allocated' node's
    457          * size and address appropriately
    458          */
    459         curr_entry->addr = addr;
    460         curr_entry->size = curr_entry->size - split_entry->size;
    461 
    462 
    463         /*
    464          * ENHANCEME: do something with the status from avl_insert
    465          */
    466 #ifndef NDEBUG
    467         nStatus =
    468 #endif /* !NDEBUG*/
    469         shr_avl_insert(mem_avl->tree, _shr_mem_avl_compare, 
    470                                  (shr_avl_datum_t*)split_entry);
    471         assert(nStatus >= 0);
    472         _shr_mem_avl_dll_insert(mem_avl, split_entry);
    473     }
    474 
    475     if (size < curr_entry->size) {
    476         /*
    477          * The search returned a free block that is greater than
    478          * what we need.  We need to split off the unused lines,
    479          * and add that back to the free tree.
    480          */
    481         pTmpVoid = NULL;
    482         pTmpVoid = sal_alloc(sizeof(*split_entry), "mem_avl");
    483         if (NULL == pTmpVoid) {
    484             /* OOSM */
    485             return( -1 );
    486         }
    487 
    488         split_entry = (shr_mem_avl_entry_pt)pTmpVoid;
    489 
    490         sal_memset(split_entry, 0, sizeof(*split_entry));
    491         split_entry->size = curr_entry->size - size;
    492         split_entry->addr = curr_entry->addr + size;
    493         split_entry->next = NULL;
    494         split_entry->prev = NULL;
    495         split_entry->self = split_entry;
    496 
    497         /*
    498          * Since we're splitting, we have to update the 'allocated' node's
    499          * size appropriately
    500          */
    501         curr_entry->size = size;
    502 
    503 
    504         /*
    505          * ENHANCEME: do something with the status from avl_insert
    506          */
    507 #ifndef NDEBUG
    508         nStatus = 
    509 #endif /* !NDEBUG*/
    510         shr_avl_insert(mem_avl->tree, _shr_mem_avl_compare, 
    511                                  (shr_avl_datum_t*)split_entry);
    512         assert( nStatus >= 0);
    513         _shr_mem_avl_dll_insert(mem_avl, split_entry);
    514     }
    515 
    516     /*
    517      * Now take care of the block we're interested in
    518      */
    519     curr_entry->used = 1;
    520 
    521     return( 0 );
    522 }
    523 /*
    524  * Doubly Linked List functions
    525  */
    526 static shr_mem_avl_entry_pt _shr_mem_avl_dll_search(shr_mem_avl_t *mem_avl,
    527                                                     unsigned int addr,
    528                                                     unsigned int loose)
    529 {
    530     shr_mem_avl_entry_pt entry;
    531     unsigned int curr_addr;
    532 
    533     assert(mem_avl);
    534 
    535     entry = mem_avl->mem_list;
    536 
    537     while (NULL != entry) {
    538         curr_addr = entry->addr;
    539         if (curr_addr == addr) {
    540             return( entry );
    541         }
    542         if ( (loose) && 
    543              (curr_addr < addr) &&
    544              ((curr_addr + entry->size - 1) > addr) ) {
    545             return( entry );
    546         }
    547 
    548         entry = entry->next;
    549     }
    550 
    551     /*
    552      * If we got here, we didn't find the appropriate entry
    553      */
    554     return( NULL );
    555 }
    556 
    557 static int _shr_mem_avl_dll_insert(shr_mem_avl_t* mem_avl,
    558                                    shr_mem_avl_entry_pt entry)
    559 {
    560     shr_mem_avl_entry_pt curr_entry;
    561     unsigned int curr_addr;
    562     unsigned int insert_addr;
    563 
    564     assert(mem_avl);
    565     assert(entry);
    566 
    567     curr_entry = mem_avl->mem_list;
    568 
    569     /*
    570      * Search for the first entry that has an address that is greater
    571      * than our insert address.  Once found, back track one entry and
    572      * insert the new one before the found
    573      * entry.  If we don't find said entry, insert it at the tail.
    574      * We assume we cannot have the same address twice in the DLL.
    575      */
    576     insert_addr = entry->addr;
    577     while (NULL != curr_entry) {
    578         curr_addr = curr_entry->addr;
    579 
    580         if (curr_addr > insert_addr) {
    581             curr_entry = curr_entry->prev;
    582             break;
    583         }
    584 
    585         if (NULL == curr_entry->next) {
    586             break;
    587         }
    588         curr_entry = curr_entry->next;
    589     }
    590 
    591     /*
    592      * Insert after the entry we found.
    593      * Since this is an ordered list, and the head is initialized
    594      * We need not worry about inserting at the head.
    595      */
    596     entry->prev = curr_entry;
    597     entry->next = curr_entry->next;
    598 /*    entry->used = 1; */
    599     curr_entry->next = entry;
    600     if (NULL != entry->next) {
    601         entry->next->prev = entry;
    602     }
    603 
    604     return( 0 );
    605 }
    606 
    607 static int _shr_mem_avl_remove(shr_mem_avl_t *mem_avl,
    608                                shr_mem_avl_entry_pt entry)
    609 {
    610     int nStatus;
    611 
    612     /*
    613      * Calls remove root if necessary
    614      */
    615     nStatus = shr_avl_delete(mem_avl->tree, _shr_mem_avl_compare, 
    616                              (shr_avl_datum_t*)entry);
    617 
    618     return( nStatus );
    619 }
    620 
    621 static int _shr_mem_avl_dll_remove(shr_mem_avl_t *mem_avl,
    622                                    shr_mem_avl_entry_pt entry)
    623 {
    624     shr_mem_avl_entry_pt prev_entry;
    625     shr_mem_avl_entry_pt next_entry;
    626 
    627     assert(mem_avl);
    628     assert(entry);
    629 
    630     prev_entry = entry->prev;
    631     next_entry = entry->next;
    632 
    633     if (NULL != prev_entry) {
    634         prev_entry->next = next_entry;
    635     }
    636 
    637     if (NULL != next_entry) {
    638         next_entry->prev = prev_entry;
    639     }
    640 
    641     return( 0 );
    642 }
    643 
    644 int shr_mem_avl_free(shr_mem_avl_t *mem_avl, unsigned int addr)
    645 {
    646     shr_mem_avl_entry_pt entry;
    647     shr_mem_avl_entry_pt prev_entry;
    648     shr_mem_avl_entry_pt next_entry;
    649 #ifndef NDEBUG
    650     int nStatus; 
    651 #endif /* !NDEBUG*/
    652     assert(mem_avl);
    653 
    654     /*
    655      * Search for our DLL entry
    656      */
    657     entry = _shr_mem_avl_dll_search(mem_avl, addr, 0);
    658     if (NULL == entry) {
    659         /*
    660          * This is bad, we couldn't find our
    661          * allocated block to free
    662          */
    663         return( -1 );
    664     }
    665 
    666     if ( !(entry->used) ) {
    667         /*
    668          * Trying to free a free block?
    669          */
    670         return( -1 );
    671     }
    672 
    673     /*
    674      * Attempt to coalesce adjacent blocks.
    675      *
    676      * We have four scenarios:
    677      *   1.  Previous block is free
    678      *   2.  Next block is free
    679      *   3.  Both Previous & Next blocks are free.
    680      *   4.  Neither Previous & Next blocks are free.
    681      */
    682     prev_entry = entry->prev;
    683     next_entry = entry->next;
    684 
    685     if (NULL != prev_entry) {
    686         /* Previous Block is free */
    687         /*
    688          * Since we want to ensure that we don't remove the root node
    689          * of the DLL, we coalesce to to previous node
    690          */
    691         if ( !(prev_entry->used) ) {
    692             _shr_mem_avl_remove(mem_avl, prev_entry);
    693             prev_entry->size += entry->size;
    694             _shr_mem_avl_dll_remove(mem_avl, entry);
    695             sal_free(entry);
    696             /*
    697              * Setup our pointer to look at the coalesced block
    698              */
    699             entry = prev_entry;
    700         }
    701     }
    702 
    703     if (NULL != next_entry) {
    704         /* Next Block is free */
    705         if ( !(next_entry->used) ) {
    706             entry->size += next_entry->size;
    707             _shr_mem_avl_remove(mem_avl, next_entry);
    708             _shr_mem_avl_dll_remove(mem_avl, next_entry);
    709             sal_free(next_entry);
    710         }
    711     }
    712 
    713     /*
    714      * Remove the used flag
    715      */
    716     entry->used = 0;
    717 
    718     /*
    719      * Add to free tree
    720      */
    721     /*
    722      * ENHANCEME: do something with the status from avl_insert
    723      */
    724 #ifndef NDEBUG
    725     nStatus =
    726 #endif /* !NDEBUG*/
    727     shr_avl_insert(mem_avl->tree, _shr_mem_avl_compare, 
    728                              (shr_avl_datum_t*)entry);
    729     assert(nStatus >= 0);
    730 
    731     return( 0);
    732 }
    733 
    734 static void shr_mem_avl_list_tree(shr_avl_entry_t* entry, int m)
    735 {
    736     shr_mem_avl_entry_pt mem_entry;
    737     int n=m;
    738     if (entry == 0) {
    739         return;
    740     }
    741     mem_entry = (shr_mem_avl_entry_pt)(&entry->datum);
    742     if (entry->right) {
    743         shr_mem_avl_list_tree(entry->right, m+1);
    744     }
    745     while (n--) {
    746         LOG_CLI((BSL_META("   ")));
    747     }
    748     LOG_CLI((BSL_META("0x%x (size:0x%x) (0x%x)\n"),mem_entry->addr, 
    749              mem_entry->size, entry->balance));
    750     if (entry->left) {
    751         shr_mem_avl_list_tree(entry->left, m+1);
    752     }
    753 }
    754 
    755 int shr_mem_avl_list_output( shr_mem_avl_t *mem_avl )
    756 {
    757     shr_mem_avl_entry_pt entry;
    758     int index;
    759 
    760     assert(mem_avl);
    761 
    762     entry = mem_avl->mem_list;
    763     LOG_CLI((BSL_META("Listing Memory Nodes:\n")));
    764     index = 0;
    765     while (NULL != entry) {
    766         LOG_CLI((BSL_META("%i:  Units: 0x%x  Addr: 0x%x Used: %i "),
    767                  index++,
    768                  entry->size,
    769                  entry->addr,
    770                  entry->used));
    771         LOG_CLI((BSL_META("This: %p Prev: %p Self: %p Next %p\n"),
    772                  (void *)entry,
    773                  (void *)entry->prev,
    774                  (void *)entry->self,
    775                  (void *)entry->next));
    776         entry = entry->next;
    777     }
    778 
    779     return( 0 );
    780 
    781 }
    782 
    783 int shr_mem_avl_free_tree_list( shr_mem_avl_t *mem_avl )
    784 {
    785     assert(mem_avl);
    786 
    787     LOG_CLI((BSL_META("Listing Free Tree:\n")));
    788     shr_mem_avl_list_tree(mem_avl->tree->root, 0);
    789 
    790     return( 0 );
    791 
    792 }
    793 
    794 int shr_mem_avl_check_mem( shr_mem_avl_t *mem_avl, 
    795                            int *edges, 
    796                            int *patches, 
    797                            int *usedCount, 
    798                            int *freeCount)
    799 {
    800     shr_mem_avl_entry_pt entry;
    801 
    802     assert(mem_avl);
    803 
    804     *edges = 0;
    805     *patches = 1;
    806     *usedCount = 0;
    807     *freeCount = 0;
    808 
    809     /*
    810      * Search for edges
    811      */
    812     entry = mem_avl->mem_list;
    813     while (NULL != entry) {
    814         if (NULL != entry->prev) {
    815             if ((entry->used) !=
    816                 (entry->prev->used) ) {
    817                 (*edges)++;
    818             }
    819         }
    820         entry = entry->next;
    821     }
    822 
    823     /*
    824      * Search for patches, and count used & free at the same time
    825      */
    826     entry = mem_avl->mem_list;
    827     while (NULL != entry) {
    828         if (NULL != entry->next) {
    829             if ((entry->used) !=
    830                 (entry->next->used)) {
    831                 (*patches)++;
    832             }
    833         }
    834 
    835         if (entry->used == 1) {
    836             (*usedCount)++;
    837         }
    838         else {
    839             (*freeCount)++;
    840         }
    841 
    842         entry = entry->next;
    843     }
    844 
    845     return( 0 );
    846 }
    847 
    848 int shr_mem_avl_free_count(shr_mem_avl_t *mem_avl, int size, int*count)
    849 {
    850     assert(mem_avl);
    851     *count = 0;
    852     _shr_mem_avl_find_free_count(mem_avl->tree->root, size, count);
    853     return( 0 );
    854 }
    855 
    856 static void _shr_mem_avl_find_free_count(shr_avl_entry_t* entry, int size, int *count)
    857 {
    858     shr_mem_avl_entry_pt mem_entry;
    859     if (entry == 0) {
    860         return;
    861     }
    862 
    863     mem_entry = (shr_mem_avl_entry_pt)(&entry->datum);
    864     if (entry->right) {
    865         _shr_mem_avl_find_free_count(entry->right, size, count);
    866     }
    867     *count = *count + (int)(mem_entry->size / size);
    868     if (entry->left) {
    869         _shr_mem_avl_find_free_count(entry->left, size, count);
    870     }
    871     return;
    872 }