⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ncbi_heapmgr.c

📁 ncbi源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_heapmgr.c,v $ * PRODUCTION Revision 1000.0  2003/10/29 16:36:50  gouriano * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.26 * PRODUCTION * =========================================================================== *//*  $Id: ncbi_heapmgr.c,v 1000.0 2003/10/29 16:36:50 gouriano Exp $ * =========================================================================== * *                            PUBLIC DOMAIN NOTICE *               National Center for Biotechnology Information * *  This software/database is a "United States Government Work" under the *  terms of the United States Copyright Act.  It was written as part of *  the author's official duties as a United States Government employee and *  thus cannot be copyrighted.  This software/database is freely available *  to the public for use. The National Library of Medicine and the U.S. *  Government have not placed any restriction on its use or reproduction. * *  Although all reasonable efforts have been taken to ensure the accuracy *  and reliability of the software and data, the NLM and the U.S. *  Government do not and cannot warrant the performance or results that *  may be obtained by using this software or data. The NLM and the U.S. *  Government disclaim all warranties, express or implied, including *  warranties of performance, merchantability or fitness for any particular *  purpose. * *  Please cite the author in any work or product based on this material. * * =========================================================================== * * Author:  Anton Lavrentiev * * Abstract: * * This is a simple heap manager with a primitive garbage collection. * The heap contains blocks of data, stored in the common contiguous pool, * each block preceded with a SHEAP_Block structure.  Low word of 'flag' * is either non-zero (True), when the block is in use, or zero (False), * when the block is vacant.  'Size' shows the length of the block in bytes, * (uninterpreted) data field of which is extended past the header * (the header size IS counted in the size of the block). * * When 'HEAP_Alloc' is called, the return value is either a heap pointer, * which points to the block header, marked as allocated and guaranteed * to have enough space to hold the requested data size; or 0 meaning, that the * heap has no more room to provide such a block (reasons for that: * heap is corrupted, heap has no provision to be expanded, expansion failed, * or the heap was attached read-only). * * An application program can then use the data field on its need, * providing not to overcome the size limit.  The current block header * can be used to find the next heap block with the use of 'size' member * (note, however, some restrictions below). * * The application program is NOT assumed to keep the returned block pointer, * as the garbage collection can occur on the next allocation attempt, * thus making any heap pointers invalid.  Instead, the application program * can keep track of the heap base (header of the very first heap block - * see 'HEAP_Create'), and the size of the heap, and can traverse the heap by * this means, or with call to 'HEAP_Walk' (described below).  * * While traversing, if the block found is no longer needed, it can be freed * with 'HEAP_Free' call, supplying the address of the block header * as an argument. * * Prior the heap use, the initialization is required, which comprises * call to either 'HEAP_Create' or 'HEAP_Attach' with the information about * the base heap pointer. 'HEAP_Create' also requires the size of initial * heap area (if there is one), and size of chunk (usually, a page size) * to be used in heap expansions (defaults to alignment if provided as 0). * Additionally (but not compulsory) the application program can provide * heap manager with 'expand' routine, which is supposed to be called, * when no more room is available in the heap, or the heap was not * preallocated (base = 0 in 'HEAP_Create'), and given the arguments: * - current heap base address (or 0 if this is the very first heap alloc), * - new required heap size (or 0 if this is the very last call to deallocate * the entire heap).  * If successful, the expand routine must return the new heap base * address (if any) of expanded heap area, and where the exact copy of * the current heap is made. * * Note that all heap base pointers must be aligned on a 'double' boundary. * Please also be warned not to store pointers to the heap area, as a * garbage collection can clobber them. Within a block, however, * it is possible to use local pointers (offsets), which remain same * regardless of garbage collections. * * For automatic traverse purposes there is a 'HEAP_Walk' call, which returns * the next block (either free, or used) from the heap.  Given a NULL-pointer, * this function returns the very first block, whereas all subsequent calls * with the argument being the last observed block results in the next block  * returned. NULL comes back when no more blocks exist in the heap. * * Note that for proper heap operations, no allocations should happen between * successive calls to 'HEAP_Walk', whereas deallocation of the seen block * is okay. * * Explicit heap traversing should not overcome the heap limit, * as any information above the limit is not maintained by the heap manager. * Every heap operation guarantees, that there are no adjacent free blocks, * only used blocks can follow each other sequentially. * * To discontinue to use the heap, 'HEAP_Destroy' or 'HEAP_Detach' can be * called. The former deallocates the heap (by means of a call to 'expand'), * the latter just removes the heap handle, retaining the heap data intact. * Later, such a heap could be used again if attached with 'HEAP_Attach'. * * Note that attached heap is in read-only mode, that is nothing can be * allocated and/or freed in that heap, as well as an attempt to call * 'HEAP_Destroy' will not destroy the heap data. * * Note also, that 'HEAP_Create' always does heap reset, that is the * memory area pointed by 'base' (if not 0) gets reformatted and lose * all previous contents. * */#include "ncbi_priv.h"#include <connect/ncbi_heapmgr.h>#include <stdlib.h>#include <string.h>struct SHEAP_tag {    void*         base;    TNCBI_Size    size;    TNCBI_Size    chunk;    FHEAP_Expand  expand;    void*         arg;    int/*bool*/   copy;    /* (!=0) keeps user's serial number if provided */};#define _HEAP_ALIGN(a, b)     (((unsigned long)(a) + (b) - 1) & ~((b) - 1))#define _HEAP_ALIGNMENT       sizeof(double)#define HEAP_ALIGN(a)         _HEAP_ALIGN(a, _HEAP_ALIGNMENT)#define HEAP_LAST             0x80000000UL#define HEAP_USED             0x0DEAD2F0UL#define HEAP_FREE             0#define HEAP_ISFREE(b)        (((b)->flag & ~HEAP_LAST) == HEAP_FREE)#define HEAP_ISUSED(b)        (((b)->flag & ~HEAP_LAST) == HEAP_USED)#define HEAP_ISLAST(b)        ((b)->flag & HEAP_LAST)HEAP HEAP_Create(void* base,       TNCBI_Size   size,                 TNCBI_Size chunk, FHEAP_Expand expand, void* arg){    SHEAP_Block* b;    HEAP heap;    if (!base != !size || !(heap = (HEAP) malloc(sizeof(*heap))))        return 0;    chunk = (TNCBI_Size) HEAP_ALIGN(chunk);    if (!base) {        size = (TNCBI_Size) _HEAP_ALIGN(sizeof(*b) + 1, chunk);        if (!size || !expand || !(base = (*expand)(0, size, arg))) {            CORE_LOGF(eLOG_Warning,                      ("Heap Create: Cannot create (size = %u)",                       (unsigned)(size ? size : sizeof(*b))));            free(heap);            return 0;        }    }    if ((void*) HEAP_ALIGN(base) != base) {        CORE_LOGF(eLOG_Warning,                  ("Heap Create: Unaligned base (0x%08lX)", (long) base));    }    if (size < (TNCBI_Size) HEAP_ALIGN(sizeof(*b) + 1)) {        CORE_LOGF(eLOG_Warning, ("Heap Create: Heap is too small (%u, %u)",                                 (unsigned) size, (unsigned) sizeof(*b)));    }    heap->base   = base;    heap->size   = size;    heap->chunk  = chunk;    heap->expand = expand;    heap->arg    = expand ? arg : 0;    heap->copy   = 0/*original*/;    b = (SHEAP_Block*) heap->base;    b->flag = HEAP_FREE | HEAP_LAST;    b->size = size;    return heap;}HEAP HEAP_AttachEx(const void* base, TNCBI_Size size){    HEAP heap;    if (!base || !size || !(heap = malloc(sizeof(*heap))))        return 0;    if ((void*) HEAP_ALIGN(base) != base) {        CORE_LOGF(eLOG_Warning,                  ("Heap Attach: Unaligned base (0x%08lX)", (long) base));    }    heap->base   = (void*) base;    heap->size   = size;    heap->chunk  = 0/*read-only*/;    heap->expand = 0;    heap->arg    = 0;    heap->copy   = 0/*original*/;    return heap;}HEAP HEAP_Attach(const void* base){    TNCBI_Size size;    SHEAP_Block* b;    if (!base)        return 0;    size = 0;    for (b = (SHEAP_Block*) base; ; b = (SHEAP_Block*)((char*) b + b->size)) {        if (!HEAP_ISUSED(b) && !HEAP_ISFREE(b)) {            CORE_LOGF(eLOG_Warning,                      ("Heap Attach: Heap corrupted (0x%08X, %u)",                       b->flag, (unsigned) b->size));            return 0;        }        size += b->size;        if (HEAP_ISLAST(b))            break;    }    return HEAP_AttachEx(base, size);}/* Check if a given block 'b' is adjacent to a free block, which * follows 'b', and/or to optionally passed previous block 'p'. * Join block(s) to form a larger free block, and return a pointer * to the next block. */static SHEAP_Block* s_HEAP_Join(SHEAP_Block* p, SHEAP_Block* b){    /* Block following 'b' */    SHEAP_Block* n = (SHEAP_Block*)((char*) b + b->size);    assert(HEAP_ISFREE(b));    if (!HEAP_ISLAST(b) && HEAP_ISFREE(n)) {        b->size += n->size;        b->flag = n->flag;        n = (SHEAP_Block*)((char*) n + n->size);    }    if (p && HEAP_ISFREE(p)) {        p->size += b->size;        p->flag = b->flag;    }    return n;}/* Collect garbage in the heap, moving all contents to the * top of the heap, and merging all free blocks at the end * in one large free block. Return pointer to that free block. */static SHEAP_Block* s_HEAP_Collect(HEAP heap){    SHEAP_Block* b = (SHEAP_Block*) heap->base, *f = 0;    while ((char*) b < (char*) heap->base + heap->size) {        if (HEAP_ISFREE(b))            f = b;        else if (HEAP_ISUSED(b) && f) {            unsigned int last = b->flag & HEAP_LAST;            TNCBI_Size save = f->size;            memmove(f, b, b->size);            f->flag &= ~HEAP_LAST;            f = (SHEAP_Block*)((char*) f + f->size);            f->flag = HEAP_FREE | last;            f->size = save;            b = s_HEAP_Join(0, f);            continue;        }        b = (SHEAP_Block*)((char*) b + b->size);    }    return f;}/* Take the block 'b' (maybe split in two, if it's roomy enough) * for use of by at most 'size' bytes (including block header). * Return the block to use if taken okay; 0 otherwise. */static SHEAP_Block* s_HEAP_Take(SHEAP_Block* b, TNCBI_Size size){    unsigned int last = b->flag & HEAP_LAST;    if (b->size >= size + sizeof(*b)) {        SHEAP_Block* n = (SHEAP_Block*)((char*) b + size);        n->flag = HEAP_FREE | last;        n->size = b->size - size;        b->flag = HEAP_USED;        b->size = size;        s_HEAP_Join(0, n);    } else        b->flag = HEAP_USED | last;    return b;}SHEAP_Block* HEAP_Alloc(HEAP heap, TNCBI_Size size){    SHEAP_Block* b, *p = 0;    TNCBI_Size free = 0;    if (!heap || size < 1) {        if (size)            CORE_LOG(eLOG_Warning, "Heap Alloc: Cannot alloc in NULL heap");        return 0;    }    if (!heap->chunk) {        CORE_LOG(eLOG_Warning, "Heap Alloc: Heap is read-only");        return 0;    }    size = (TNCBI_Size) HEAP_ALIGN(sizeof(*b) + size);    b = (SHEAP_Block*) heap->base;    while ((char*) b < (char*) heap->base + heap->size) {        if (HEAP_ISFREE(b)) {            /* if an empty, large enough block found, then take it! */            if (b->size >= size)                return s_HEAP_Take(b, size);            free += b->size;        } else if (!HEAP_ISUSED(b)) {            CORE_LOGF(eLOG_Warning,                      ("Heap Alloc: Heap corrupted (0x%08X, %u)",                       b->flag, (unsigned) b->size));            return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -