ncbi_heapmgr.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:22k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_heapmgr.c,v $
  4.  * PRODUCTION Revision 1000.0  2003/10/29 16:36:50  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.26
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_heapmgr.c,v 1000.0 2003/10/29 16:36:50 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Anton Lavrentiev
  35.  *
  36.  * Abstract:
  37.  *
  38.  * This is a simple heap manager with a primitive garbage collection.
  39.  * The heap contains blocks of data, stored in the common contiguous pool,
  40.  * each block preceded with a SHEAP_Block structure.  Low word of 'flag'
  41.  * is either non-zero (True), when the block is in use, or zero (False),
  42.  * when the block is vacant.  'Size' shows the length of the block in bytes,
  43.  * (uninterpreted) data field of which is extended past the header
  44.  * (the header size IS counted in the size of the block).
  45.  *
  46.  * When 'HEAP_Alloc' is called, the return value is either a heap pointer,
  47.  * which points to the block header, marked as allocated and guaranteed
  48.  * to have enough space to hold the requested data size; or 0 meaning, that the
  49.  * heap has no more room to provide such a block (reasons for that:
  50.  * heap is corrupted, heap has no provision to be expanded, expansion failed,
  51.  * or the heap was attached read-only).
  52.  *
  53.  * An application program can then use the data field on its need,
  54.  * providing not to overcome the size limit.  The current block header
  55.  * can be used to find the next heap block with the use of 'size' member
  56.  * (note, however, some restrictions below).
  57.  *
  58.  * The application program is NOT assumed to keep the returned block pointer,
  59.  * as the garbage collection can occur on the next allocation attempt,
  60.  * thus making any heap pointers invalid.  Instead, the application program
  61.  * can keep track of the heap base (header of the very first heap block -
  62.  * see 'HEAP_Create'), and the size of the heap, and can traverse the heap by
  63.  * this means, or with call to 'HEAP_Walk' (described below). 
  64.  *
  65.  * While traversing, if the block found is no longer needed, it can be freed
  66.  * with 'HEAP_Free' call, supplying the address of the block header
  67.  * as an argument.
  68.  *
  69.  * Prior the heap use, the initialization is required, which comprises
  70.  * call to either 'HEAP_Create' or 'HEAP_Attach' with the information about
  71.  * the base heap pointer. 'HEAP_Create' also requires the size of initial
  72.  * heap area (if there is one), and size of chunk (usually, a page size)
  73.  * to be used in heap expansions (defaults to alignment if provided as 0).
  74.  * Additionally (but not compulsory) the application program can provide
  75.  * heap manager with 'expand' routine, which is supposed to be called,
  76.  * when no more room is available in the heap, or the heap was not
  77.  * preallocated (base = 0 in 'HEAP_Create'), and given the arguments:
  78.  * - current heap base address (or 0 if this is the very first heap alloc),
  79.  * - new required heap size (or 0 if this is the very last call to deallocate
  80.  * the entire heap). 
  81.  * If successful, the expand routine must return the new heap base
  82.  * address (if any) of expanded heap area, and where the exact copy of
  83.  * the current heap is made.
  84.  *
  85.  * Note that all heap base pointers must be aligned on a 'double' boundary.
  86.  * Please also be warned not to store pointers to the heap area, as a
  87.  * garbage collection can clobber them. Within a block, however,
  88.  * it is possible to use local pointers (offsets), which remain same
  89.  * regardless of garbage collections.
  90.  *
  91.  * For automatic traverse purposes there is a 'HEAP_Walk' call, which returns
  92.  * the next block (either free, or used) from the heap.  Given a NULL-pointer,
  93.  * this function returns the very first block, whereas all subsequent calls
  94.  * with the argument being the last observed block results in the next block 
  95.  * returned. NULL comes back when no more blocks exist in the heap.
  96.  *
  97.  * Note that for proper heap operations, no allocations should happen between
  98.  * successive calls to 'HEAP_Walk', whereas deallocation of the seen block
  99.  * is okay.
  100.  *
  101.  * Explicit heap traversing should not overcome the heap limit,
  102.  * as any information above the limit is not maintained by the heap manager.
  103.  * Every heap operation guarantees, that there are no adjacent free blocks,
  104.  * only used blocks can follow each other sequentially.
  105.  *
  106.  * To discontinue to use the heap, 'HEAP_Destroy' or 'HEAP_Detach' can be
  107.  * called. The former deallocates the heap (by means of a call to 'expand'),
  108.  * the latter just removes the heap handle, retaining the heap data intact.
  109.  * Later, such a heap could be used again if attached with 'HEAP_Attach'.
  110.  *
  111.  * Note that attached heap is in read-only mode, that is nothing can be
  112.  * allocated and/or freed in that heap, as well as an attempt to call
  113.  * 'HEAP_Destroy' will not destroy the heap data.
  114.  *
  115.  * Note also, that 'HEAP_Create' always does heap reset, that is the
  116.  * memory area pointed by 'base' (if not 0) gets reformatted and lose
  117.  * all previous contents.
  118.  *
  119.  */
  120. #include "ncbi_priv.h"
  121. #include <connect/ncbi_heapmgr.h>
  122. #include <stdlib.h>
  123. #include <string.h>
  124. struct SHEAP_tag {
  125.     void*         base;
  126.     TNCBI_Size    size;
  127.     TNCBI_Size    chunk;
  128.     FHEAP_Expand  expand;
  129.     void*         arg;
  130.     int/*bool*/   copy;    /* (!=0) keeps user's serial number if provided */
  131. };
  132. #define _HEAP_ALIGN(a, b)     (((unsigned long)(a) + (b) - 1) & ~((b) - 1))
  133. #define _HEAP_ALIGNMENT       sizeof(double)
  134. #define HEAP_ALIGN(a)         _HEAP_ALIGN(a, _HEAP_ALIGNMENT)
  135. #define HEAP_LAST             0x80000000UL
  136. #define HEAP_USED             0x0DEAD2F0UL
  137. #define HEAP_FREE             0
  138. #define HEAP_ISFREE(b)        (((b)->flag & ~HEAP_LAST) == HEAP_FREE)
  139. #define HEAP_ISUSED(b)        (((b)->flag & ~HEAP_LAST) == HEAP_USED)
  140. #define HEAP_ISLAST(b)        ((b)->flag & HEAP_LAST)
  141. HEAP HEAP_Create(void* base,       TNCBI_Size   size,
  142.                  TNCBI_Size chunk, FHEAP_Expand expand, void* arg)
  143. {
  144.     SHEAP_Block* b;
  145.     HEAP heap;
  146.     if (!base != !size || !(heap = (HEAP) malloc(sizeof(*heap))))
  147.         return 0;
  148.     chunk = (TNCBI_Size) HEAP_ALIGN(chunk);
  149.     if (!base) {
  150.         size = (TNCBI_Size) _HEAP_ALIGN(sizeof(*b) + 1, chunk);
  151.         if (!size || !expand || !(base = (*expand)(0, size, arg))) {
  152.             CORE_LOGF(eLOG_Warning,
  153.                       ("Heap Create: Cannot create (size = %u)",
  154.                        (unsigned)(size ? size : sizeof(*b))));
  155.             free(heap);
  156.             return 0;
  157.         }
  158.     }
  159.     if ((void*) HEAP_ALIGN(base) != base) {
  160.         CORE_LOGF(eLOG_Warning,
  161.                   ("Heap Create: Unaligned base (0x%08lX)", (long) base));
  162.     }
  163.     if (size < (TNCBI_Size) HEAP_ALIGN(sizeof(*b) + 1)) {
  164.         CORE_LOGF(eLOG_Warning, ("Heap Create: Heap is too small (%u, %u)",
  165.                                  (unsigned) size, (unsigned) sizeof(*b)));
  166.     }
  167.     heap->base   = base;
  168.     heap->size   = size;
  169.     heap->chunk  = chunk;
  170.     heap->expand = expand;
  171.     heap->arg    = expand ? arg : 0;
  172.     heap->copy   = 0/*original*/;
  173.     b = (SHEAP_Block*) heap->base;
  174.     b->flag = HEAP_FREE | HEAP_LAST;
  175.     b->size = size;
  176.     return heap;
  177. }
  178. HEAP HEAP_AttachEx(const void* base, TNCBI_Size size)
  179. {
  180.     HEAP heap;
  181.     if (!base || !size || !(heap = malloc(sizeof(*heap))))
  182.         return 0;
  183.     if ((void*) HEAP_ALIGN(base) != base) {
  184.         CORE_LOGF(eLOG_Warning,
  185.                   ("Heap Attach: Unaligned base (0x%08lX)", (long) base));
  186.     }
  187.     heap->base   = (void*) base;
  188.     heap->size   = size;
  189.     heap->chunk  = 0/*read-only*/;
  190.     heap->expand = 0;
  191.     heap->arg    = 0;
  192.     heap->copy   = 0/*original*/;
  193.     return heap;
  194. }
  195. HEAP HEAP_Attach(const void* base)
  196. {
  197.     TNCBI_Size size;
  198.     SHEAP_Block* b;
  199.     if (!base)
  200.         return 0;
  201.     size = 0;
  202.     for (b = (SHEAP_Block*) base; ; b = (SHEAP_Block*)((char*) b + b->size)) {
  203.         if (!HEAP_ISUSED(b) && !HEAP_ISFREE(b)) {
  204.             CORE_LOGF(eLOG_Warning,
  205.                       ("Heap Attach: Heap corrupted (0x%08X, %u)",
  206.                        b->flag, (unsigned) b->size));
  207.             return 0;
  208.         }
  209.         size += b->size;
  210.         if (HEAP_ISLAST(b))
  211.             break;
  212.     }
  213.     return HEAP_AttachEx(base, size);
  214. }
  215. /* Check if a given block 'b' is adjacent to a free block, which
  216.  * follows 'b', and/or to optionally passed previous block 'p'.
  217.  * Join block(s) to form a larger free block, and return a pointer
  218.  * to the next block.
  219.  */
  220. static SHEAP_Block* s_HEAP_Join(SHEAP_Block* p, SHEAP_Block* b)
  221. {
  222.     /* Block following 'b' */
  223.     SHEAP_Block* n = (SHEAP_Block*)((char*) b + b->size);
  224.     assert(HEAP_ISFREE(b));
  225.     if (!HEAP_ISLAST(b) && HEAP_ISFREE(n)) {
  226.         b->size += n->size;
  227.         b->flag = n->flag;
  228.         n = (SHEAP_Block*)((char*) n + n->size);
  229.     }
  230.     if (p && HEAP_ISFREE(p)) {
  231.         p->size += b->size;
  232.         p->flag = b->flag;
  233.     }
  234.     return n;
  235. }
  236. /* Collect garbage in the heap, moving all contents to the
  237.  * top of the heap, and merging all free blocks at the end
  238.  * in one large free block. Return pointer to that free block.
  239.  */
  240. static SHEAP_Block* s_HEAP_Collect(HEAP heap)
  241. {
  242.     SHEAP_Block* b = (SHEAP_Block*) heap->base, *f = 0;
  243.     while ((char*) b < (char*) heap->base + heap->size) {
  244.         if (HEAP_ISFREE(b))
  245.             f = b;
  246.         else if (HEAP_ISUSED(b) && f) {
  247.             unsigned int last = b->flag & HEAP_LAST;
  248.             TNCBI_Size save = f->size;
  249.             memmove(f, b, b->size);
  250.             f->flag &= ~HEAP_LAST;
  251.             f = (SHEAP_Block*)((char*) f + f->size);
  252.             f->flag = HEAP_FREE | last;
  253.             f->size = save;
  254.             b = s_HEAP_Join(0, f);
  255.             continue;
  256.         }
  257.         b = (SHEAP_Block*)((char*) b + b->size);
  258.     }
  259.     return f;
  260. }
  261. /* Take the block 'b' (maybe split in two, if it's roomy enough)
  262.  * for use of by at most 'size' bytes (including block header).
  263.  * Return the block to use if taken okay; 0 otherwise.
  264.  */
  265. static SHEAP_Block* s_HEAP_Take(SHEAP_Block* b, TNCBI_Size size)
  266. {
  267.     unsigned int last = b->flag & HEAP_LAST;
  268.     if (b->size >= size + sizeof(*b)) {
  269.         SHEAP_Block* n = (SHEAP_Block*)((char*) b + size);
  270.         n->flag = HEAP_FREE | last;
  271.         n->size = b->size - size;
  272.         b->flag = HEAP_USED;
  273.         b->size = size;
  274.         s_HEAP_Join(0, n);
  275.     } else
  276.         b->flag = HEAP_USED | last;
  277.     return b;
  278. }
  279. SHEAP_Block* HEAP_Alloc(HEAP heap, TNCBI_Size size)
  280. {
  281.     SHEAP_Block* b, *p = 0;
  282.     TNCBI_Size free = 0;
  283.     if (!heap || size < 1) {
  284.         if (size)
  285.             CORE_LOG(eLOG_Warning, "Heap Alloc: Cannot alloc in NULL heap");
  286.         return 0;
  287.     }
  288.     if (!heap->chunk) {
  289.         CORE_LOG(eLOG_Warning, "Heap Alloc: Heap is read-only");
  290.         return 0;
  291.     }
  292.     size = (TNCBI_Size) HEAP_ALIGN(sizeof(*b) + size);
  293.     b = (SHEAP_Block*) heap->base;
  294.     while ((char*) b < (char*) heap->base + heap->size) {
  295.         if (HEAP_ISFREE(b)) {
  296.             /* if an empty, large enough block found, then take it! */
  297.             if (b->size >= size)
  298.                 return s_HEAP_Take(b, size);
  299.             free += b->size;
  300.         } else if (!HEAP_ISUSED(b)) {
  301.             CORE_LOGF(eLOG_Warning,
  302.                       ("Heap Alloc: Heap corrupted (0x%08X, %u)",
  303.                        b->flag, (unsigned) b->size));
  304.             return 0;
  305.         }
  306.         p = b;
  307.         b = (SHEAP_Block*)((char*) b + b->size);
  308.     }
  309.     /* Heap exhausted, no free block found */
  310.     if (free >= size)
  311.         b = s_HEAP_Collect(heap);
  312.     else if (!heap->expand)
  313.         return 0;
  314.     else {
  315.         TNCBI_Size hsize =
  316.             (TNCBI_Size) _HEAP_ALIGN(heap->size + size, heap->chunk);
  317.         ptrdiff_t dp = (char*) p - (char*) heap->base;
  318.         void* base;
  319.         if (!(base = (*heap->expand)(heap->base, hsize, heap->arg)))
  320.             return 0;
  321.         p = (SHEAP_Block*)((char*) base + dp);
  322.         if (!HEAP_ISLAST(p))
  323.             CORE_LOG(eLOG_Warning, "Heap Alloc: Last block lost");
  324.         if (HEAP_ISUSED(p)) {
  325.             p->flag &= ~HEAP_LAST;
  326.             /* New block is the very top on the heap */
  327.             b = (SHEAP_Block*)((char*) base + heap->size);
  328.             b->size = hsize - heap->size;
  329.             b->flag = HEAP_FREE | HEAP_LAST;
  330.         } else {
  331.             /* Extend last free block */
  332.             p->size += hsize - heap->size;
  333.             b = p;
  334.         }
  335.         heap->base = base;
  336.         heap->size = hsize;
  337.     }
  338.     assert(b && HEAP_ISFREE(b) && b->size >= size);
  339.     return s_HEAP_Take(b, size);
  340. }
  341. void HEAP_Free(HEAP heap, SHEAP_Block* ptr)
  342. {
  343.     SHEAP_Block* b, *p = 0;
  344.     if (!heap || !ptr) {
  345.         if (ptr)
  346.             CORE_LOG(eLOG_Warning, "Heap Free: Cannot free in NULL heap");
  347.         return;
  348.     }
  349.     if (!heap->chunk) {
  350.         CORE_LOG(eLOG_Warning, "Heap Free: Heap is read-only");
  351.         return;
  352.     }
  353.     b = (SHEAP_Block*) heap->base;
  354.     while ((char*) b < (char*) heap->base + heap->size) {
  355.         if (HEAP_ISFREE(b)) {
  356.             if (b == ptr) {
  357.                 CORE_LOG(eLOG_Warning, "Heap Free: Freeing free block");
  358.                 return;
  359.             }
  360.         } else if (HEAP_ISUSED(b)) {
  361.             if (b == ptr) {
  362.                 b->flag = HEAP_FREE | (b->flag & HEAP_LAST);
  363.                 s_HEAP_Join(p, b);
  364.                 return;
  365.             }
  366.         } else {
  367.             CORE_LOGF(eLOG_Warning,
  368.                       ("Heap Free: Heap corrupted (0x%08X, %u)",
  369.                        b->flag, (unsigned) b->size));
  370.             return;
  371.         }
  372.         p = b;
  373.         b = (SHEAP_Block*)((char*) p + p->size);
  374.     }
  375.     CORE_LOG(eLOG_Warning, "Heap Free: Block not found");
  376. }
  377. SHEAP_Block* HEAP_Walk(const HEAP heap, const SHEAP_Block* p)
  378. {
  379.     SHEAP_Block* b;
  380.     if (!heap) {
  381.         CORE_LOG(eLOG_Warning, "Heap Walk: NULL heap");
  382.         return 0;
  383.     }
  384.     if (!p ||
  385.         ((char*) p >= (char*) heap->base &&
  386.          (char*) p <  (char*) heap->base + heap->size)) {
  387.         b = (SHEAP_Block*)(p ? (char*) p + p->size : (char*) heap->base);
  388.         if ((char*) b < (char*) heap->base + heap->size) {
  389.             if (b->size >= sizeof(*b) &&
  390.                 b->size == (TNCBI_Size) HEAP_ALIGN(b->size) &&
  391.                 (char*) b + b->size <= (char*) heap->base + heap->size &&
  392.                 (HEAP_ISFREE(b) || HEAP_ISUSED(b))) {
  393.                 /* Block 'b' seems valid, but... */
  394.                 if (!p)
  395.                     return b;
  396.                 if (HEAP_ISLAST(p))
  397.                     CORE_LOG(eLOG_Warning, "Heap Walk: Misplaced last block");
  398.                 else if (HEAP_ISFREE(b) && HEAP_ISFREE(p)) {
  399.                     const SHEAP_Block* c = (const SHEAP_Block*) heap->base;
  400.                     while ((char*) c < (char*) p) {
  401.                         if (HEAP_ISFREE(c) &&
  402.                             (char*) c + c->size >= (char*) b + b->size)
  403.                             break;
  404.                         c = (SHEAP_Block*)((char*) c + c->size);
  405.                     }
  406.                     if ((char*) c < (char*) p)
  407.                         return b;
  408.                     CORE_LOG(eLOG_Warning, "Heap Walk: Adjacent free blocks");
  409.                 } else
  410.                     return b;
  411.             } else
  412.                 CORE_LOGF(eLOG_Warning,
  413.                           ("Heap Walk: Heap corrupted (0x%08X, %u)",
  414.                            b->flag, (unsigned) b->size));
  415.         } else if ((char*) b > (char*) heap->base + heap->size)
  416.             CORE_LOG(eLOG_Warning, "Heap Walk: Heap corrupted");
  417.         else if (!HEAP_ISLAST(p))
  418.             CORE_LOG(eLOG_Warning, "Heap Walk: Last block lost");
  419.     } else
  420.         CORE_LOG(eLOG_Warning, "Heap Walk: Alien pointer passed");
  421.     return 0;
  422. }
  423. TNCBI_Size HEAP_Trim(HEAP heap)
  424. {
  425.     TNCBI_Size   size, last_size;
  426.     SHEAP_Block* f;
  427.     if (!heap)
  428.         return 0;
  429.     if (!heap->chunk) {
  430.         CORE_LOG(eLOG_Error, "Heap Trim: Heap is read-only");
  431.         return 0;
  432.     }
  433.     if (!(f =s_HEAP_Collect(heap)) || HEAP_ISUSED(f) || f->size < heap->chunk){
  434.         last_size = 0;
  435.         size      = heap->size;
  436.     } else if ((char*) f != heap->base) {
  437.         assert(f->size >= _HEAP_ALIGNMENT);
  438.         last_size = f->size % heap->chunk;
  439.         if (last_size) {
  440.             if (last_size < _HEAP_ALIGNMENT)
  441.                 last_size += heap->chunk;
  442.             size = heap->size - f->size + last_size;
  443.         } else {
  444.             SHEAP_Block* b = (SHEAP_Block*) heap->base, *p = 0;
  445.             while (b != f) {
  446.                 p = b;
  447.                 b = (SHEAP_Block*)((char*) b + b->size);
  448.             }
  449.             size = heap->size - f->size;
  450.             assert(p);
  451.             f = p;
  452.         }
  453.     } else {
  454.         last_size = heap->chunk;
  455.         size      = heap->chunk;
  456.     }
  457.     assert(size % heap->chunk == 0);
  458.     if (heap->expand) {
  459.         void* base = (*heap->expand)(heap->base, size, heap->arg);
  460.         if (!base)
  461.             return 0;
  462.         if (f) {
  463.             ptrdiff_t dp = (char*) f - (char*) heap->base;
  464.             f = (SHEAP_Block*)((char*) base + dp);
  465.             f->flag |= HEAP_LAST;
  466.             if (last_size)
  467.                 f->size = last_size;
  468.         }
  469.         heap->base = base;
  470.         heap->size = size;
  471.     } else if (size != heap->size)
  472.         CORE_LOG(eLOG_Error, "Heap Trim: Heap is not trimmable");
  473.     return heap->size;
  474. }
  475. HEAP HEAP_CopySerial(const HEAP heap, size_t extra, int serial)
  476. {
  477.     HEAP   newheap;
  478.     void*  newbase;
  479.     extra = HEAP_ALIGN(extra);
  480.     if (!heap ||
  481.         !(newbase = malloc(HEAP_ALIGN(heap->size) + extra + sizeof(*newheap))))
  482.         return 0;
  483.     memcpy(newbase, heap->base, heap->size);
  484.     newheap = (HEAP)((char*) newbase + HEAP_ALIGN(heap->size) + extra);
  485.     newheap->base   = newbase;
  486.     newheap->size   = heap->size;
  487.     newheap->chunk  = 0/*read-only*/;
  488.     newheap->expand = 0;
  489.     newheap->arg    = 0;
  490.     newheap->copy   = serial ? serial : 1/*copy*/;
  491.     return newheap;
  492. }
  493. void HEAP_Detach(HEAP heap)
  494. {
  495.     if (heap)
  496.         free(heap->copy ? heap->base : heap);
  497. }
  498. void HEAP_Destroy(HEAP heap)
  499. {
  500.     if (heap) {
  501.         if (!heap->chunk && !heap->copy)
  502.             CORE_LOG(eLOG_Warning, "Heap Destroy: Heap is read-only");
  503.         else if (heap->expand/*NB: false for heap copies*/)
  504.             (*heap->expand)(heap->base, 0, heap->arg);
  505.         HEAP_Detach(heap);
  506.     }
  507. }
  508. void* HEAP_Base(const HEAP heap)
  509. {
  510.     return heap ? heap->base : 0;
  511. }
  512. TNCBI_Size HEAP_Size(const HEAP heap)
  513. {
  514.     return heap ? heap->size : 0;
  515. }
  516. int HEAP_Serial(const HEAP heap)
  517. {
  518.     return heap ? heap->copy : 0;
  519. }
  520. /*
  521.  * --------------------------------------------------------------------------
  522.  * $Log: ncbi_heapmgr.c,v $
  523.  * Revision 1000.0  2003/10/29 16:36:50  gouriano
  524.  * PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.26
  525.  *
  526.  * Revision 6.26  2003/10/02 14:52:23  lavr
  527.  * Wrapped long lines in the change log
  528.  *
  529.  * Revision 6.25  2003/09/24 02:56:55  ucko
  530.  * HEAP_AttachEx: size_t -> TNCBI_Size per prototype (needed on 64-bit archs)
  531.  *
  532.  * Revision 6.24  2003/09/23 21:06:30  lavr
  533.  * +HEAP_AttachEx()
  534.  *
  535.  * Revision 6.23  2003/08/28 21:09:58  lavr
  536.  * Accept (and allocate) additional heap extent in HEAP_CopySerial()
  537.  *
  538.  * Revision 6.22  2003/08/25 16:53:37  lavr
  539.  * Add/remove spaces here and there to comply with coding rules...
  540.  *
  541.  * Revision 6.21  2003/08/25 16:47:08  lavr
  542.  * Fix in pointer arith since the base changed from "char*" to "void*"
  543.  *
  544.  * Revision 6.20  2003/08/25 14:50:50  lavr
  545.  * Heap arena ptrs changed to be "void*";  expand routine to take user arg
  546.  *
  547.  * Revision 6.19  2003/08/11 19:08:04  lavr
  548.  * HEAP_Attach() reimplemented via HEAP_AttachEx() [not public yet]
  549.  * HEAP_Trim() fixed to call expansion routine where applicable
  550.  *
  551.  * Revision 6.18  2003/07/31 17:54:03  lavr
  552.  * +HEAP_Trim()
  553.  *
  554.  * Revision 6.17  2003/03/24 19:45:15  lavr
  555.  * Added few minor changes and comments
  556.  *
  557.  * Revision 6.16  2002/08/16 15:37:22  lavr
  558.  * Warn if allocation attempted on a NULL heap
  559.  *
  560.  * Revision 6.15  2002/08/12 15:15:15  lavr
  561.  * More thorough check for the free-in-the-middle heap blocks
  562.  *
  563.  * Revision 6.14  2002/04/13 06:33:52  lavr
  564.  * +HEAP_Base(), +HEAP_Size(), +HEAP_Serial(), new HEAP_CopySerial()
  565.  *
  566.  * Revision 6.13  2001/07/31 15:07:58  lavr
  567.  * Added paranoia log message: freeing a block in a NULL heap
  568.  *
  569.  * Revision 6.12  2001/07/13 20:09:27  lavr
  570.  * If remaining space in a block is equal to block header,
  571.  * do not leave this space as a padding of the block been allocated,
  572.  * but instead form a new block consisting only of the header.
  573.  * The block becomes a subject for a later garbage collecting.
  574.  *
  575.  * Revision 6.11  2001/07/03 20:24:03  lavr
  576.  * Added function: HEAP_Copy()
  577.  *
  578.  * Revision 6.10  2001/06/25 15:32:41  lavr
  579.  * Typo fixed
  580.  *
  581.  * Revision 6.9  2001/06/19 22:22:56  juran
  582.  * Heed warning:  Make s_HEAP_Take() static
  583.  *
  584.  * Revision 6.8  2001/06/19 19:12:01  lavr
  585.  * Type change: size_t -> TNCBI_Size; time_t -> TNCBI_Time
  586.  *
  587.  * Revision 6.7  2001/03/02 20:08:26  lavr
  588.  * Typos fixed
  589.  *
  590.  * Revision 6.6  2001/02/14 22:03:09  lavr
  591.  * 0x... constants explicitly made unsigned
  592.  *
  593.  * Revision 6.5  2001/01/12 23:51:39  lavr
  594.  * Message logging modified for use LOG facility only
  595.  *
  596.  * Revision 6.4  2000/05/23 21:41:07  lavr
  597.  * Alignment changed to 'double'
  598.  *
  599.  * Revision 6.3  2000/05/17 14:22:30  lavr
  600.  * Small cosmetic changes
  601.  *
  602.  * Revision 6.2  2000/05/16 15:06:05  lavr
  603.  * Minor changes for format <-> argument correspondence in warnings
  604.  *
  605.  * Revision 6.1  2000/05/12 18:33:44  lavr
  606.  * First working revision
  607.  *
  608.  * ==========================================================================
  609.  */