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

📄 sepmetaimpl.inl

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 INL
📖 第 1 页 / 共 2 页
字号:
#ifndef CYGONCE_MEMALLOC_SEPMETAIMPL_INL
#define CYGONCE_MEMALLOC_SEPMETAIMPL_INL

//==========================================================================
//
//      sepmetaimpl.inl
//
//      Variable block memory pool with separate metadata class declarations
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    jlarmour
// Contributors: hmt
// Date:         2001-06-28
// Purpose:      Define Sepmetaimpl class interface
// Description:  Inline class for constructing a variable block allocator
//               with separate metadata.
// Usage:        #include <cyg/memalloc/sepmetaimpl.hxx>
//
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/system.h>
#ifdef CYGPKG_ISOINFRA
# include <pkgconf/isoinfra.h>
#endif
#include <pkgconf/memalloc.h>
#include <cyg/memalloc/sepmetaimpl.hxx>

#include <cyg/infra/cyg_ass.h>           // assertion support
#include <cyg/infra/cyg_trac.h>          // tracing support

// Simple allocator

// The memory block lists are doubly linked lists. One for all alloced
// blocks, one for all free blocks. There's also a list of unused
// metadata from the metadata pool.  The head of the
// list has the same structure but its memnext/memprev fields are zero.
// Always having at least one item on the list simplifies the alloc and
// free code.
#ifdef CYGINT_ISO_STRING_MEMFUNCS
# include <string.h>
#endif

inline void
Cyg_Mempool_Sepmeta_Implementation::copy_data( cyg_uint8 *dst, 
                                               cyg_uint8 *src, 
                                               cyg_int32 nbytes )
{
#ifdef CYGINT_ISO_STRING_MEMFUNCS
    memmove( dst, src, nbytes );
#else
    if ((src < dst) && (dst < (src + nbytes))) {
        // Have to copy backwards
        src += nbytes;
        dst += nbytes;
        while (nbytes--) {
            *--dst = *--src;
        }
    } else {
        while (nbytes--) {
            *dst++ = *src++;
        }
    }
#endif
}

inline cyg_uint8 *
Cyg_Mempool_Sepmeta_Implementation::alignup( cyg_uint8 *addr )
{
    return (cyg_uint8 *)((cyg_int32)(addr + alignment-1) & -alignment);
}

inline cyg_uint8 *
Cyg_Mempool_Sepmeta_Implementation::aligndown( cyg_uint8 *addr )
{
    return (cyg_uint8 *)((cyg_int32)addr & -alignment);
}

inline cyg_uint8 *
Cyg_Mempool_Sepmeta_Implementation::alignmetaup( cyg_uint8 *addr )
{
    const size_t memdqalign = __alignof__ (struct memdq);
    return (cyg_uint8 *)((cyg_int32)(addr + memdqalign-1) & -memdqalign);
}

inline cyg_uint8 *
Cyg_Mempool_Sepmeta_Implementation::alignmetadown( cyg_uint8 *addr )
{
    const size_t memdqalign = __alignof__ (struct memdq);
    return (cyg_uint8 *)((cyg_int32)addr & -memdqalign);
}

// return the alloced dq at mem 
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
Cyg_Mempool_Sepmeta_Implementation::find_alloced_dq( cyg_uint8 *mem )
{
    struct memdq *dq=allocedhead.next;

    while (dq->mem != mem ) {
        CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
        CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq");
        if (dq->next == &memend) // address not found!
            return NULL;
        dq = dq->next;
    }
    return dq;
}

// returns a free dq of at least size, or NULL if none
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
Cyg_Mempool_Sepmeta_Implementation::find_free_dq( cyg_int32 size )
{
    struct memdq *dq = freehead.next;

    while ( (dq->memnext->mem - dq->mem) < size ) {
        CYG_ASSERT( dq->next->prev==dq, "Bad link in dq");
        CYG_ASSERT( dq->memnext->memprev==dq, "Bad link in mem dq");
        if (dq->next == &freehead) { // reached end of list
            return NULL;
        }
        dq = dq->next; // next on free list
    }
    return dq;
}

// returns the free dq following mem
inline struct Cyg_Mempool_Sepmeta_Implementation::memdq *
Cyg_Mempool_Sepmeta_Implementation::find_free_dq_slot( cyg_uint8 *mem )
{
    struct memdq *dq;
    for (dq = freehead.next; dq->mem < mem; dq = dq->next) {
        if ( dq == &freehead ) // wrapped round
            break;
    }
    return dq;
}

inline void
Cyg_Mempool_Sepmeta_Implementation::check_free_memdq( struct memdq *dq )
{
    if (dq == &freehead)
        return;
    CYG_ASSERT(dq->memnext->memprev == dq, "corrupted free dq #1");
    CYG_ASSERT(dq->next->prev == dq, "corrupted free dq #2");
    CYG_ASSERT(dq->memprev->memnext == dq, "corrupted free dq #3");
    CYG_ASSERT(dq->prev->next == dq, "corrupted free dq #4");
    CYG_ASSERT(dq->memnext->mem > dq->mem, "free dq mem not sorted #1");
    if (dq->memprev != &memend)
        CYG_ASSERT(dq->memprev->mem < dq->mem, "free dq mem not sorted #2");
}

inline void
Cyg_Mempool_Sepmeta_Implementation::check_alloced_memdq( struct memdq *dq )
{
    CYG_ASSERT(dq->memnext->memprev == dq, "corrupted alloced dq #1");
    CYG_ASSERT(dq->next->prev == dq, "corrupted alloced dq #2");
    CYG_ASSERT(dq->memprev->memnext == dq, "corrupted alloced dq #3");
    CYG_ASSERT(dq->prev->next == dq, "corrupted alloced dq #4");
    if (dq != &memend)
        CYG_ASSERT(dq->memnext->mem > dq->mem, "alloced dq mem not sorted #1");
    if (dq->memprev != &memhead)
        CYG_ASSERT(dq->memprev->mem < dq->mem, "alloced dq mem not sorted #2");
}

// -------------------------------------------------------------------------

inline void
Cyg_Mempool_Sepmeta_Implementation::insert_free_block( struct memdq *dq )
{
    // scan for correct slot in the sorted free list
    struct memdq *fdq = find_free_dq_slot( dq->mem );

    CYG_ASSERT(fdq != &freehead ? fdq->mem > dq->mem : 1,
               "Block address is already in freelist");

    check_free_memdq(fdq);

    if (dq->memnext == fdq) {
        // we can coalesce these two together
        // adjust fdq's mem address backwards to include dq
        fdq->mem = dq->mem;
        // and remove dq
        fdq->memprev = dq->memprev;
        fdq->memprev->memnext = fdq;
        // Don't need to adjust fdq's next/prev links as it stays in the
        // same place in the free list

        // dq is now redundant so return to metadata free list
        dq->next = freemetahead;
        freemetahead = dq;

        // reset dq
        dq = fdq;
    } else {
        // insert behind fdq
        dq->next = fdq;
        dq->prev = fdq->prev;
        fdq->prev = dq;
        dq->prev->next = dq;
    }

    check_free_memdq(dq);

    // maybe also coalesce backwards
    if (dq->memprev == dq->prev) {
        // adjust dq's mem address backwards to include dq->prev
        dq->mem = dq->prev->mem;

        // return dq->prev to metadata free list
        dq->prev->next = freemetahead;
        freemetahead = dq->prev;

        // and remove dq->prev from mem list
        dq->memprev = dq->prev->memprev;
        dq->memprev->memnext = dq;
        // and free list
        dq->prev = dq->prev->prev;
        dq->prev->next = dq;

        check_free_memdq(dq);
    }
}

// -------------------------------------------------------------------------
#include <cyg/infra/diag.h>
inline
Cyg_Mempool_Sepmeta_Implementation::Cyg_Mempool_Sepmeta_Implementation(
        cyg_uint8 *base,
        cyg_int32 size,
        CYG_ADDRWORD consargs)
{
    CYG_REPORT_FUNCTION();
    struct constructorargs *args = (struct constructorargs *)consargs;
    CYG_CHECK_DATA_PTRC( args );

    alignment = args->alignment;

    CYG_ASSERT( alignment > 0, "Bad alignment" );
    CYG_ASSERT( 0!=alignment, "alignment is zero" );
    CYG_ASSERT( 0==(alignment & alignment-1), "alignment not a power of 2" );

    obase=base;
    osize=size;
    metabase = args->metabase;
    metasize = args->metasize;

    // bottom is set to the lowest available address given the alignment. 
    bottom = alignup( base );
    cyg_uint8 *metabottom = alignmetaup( metabase );

    // because we split free blocks by allocating memory from the end, not
    // the beginning, then to preserve alignment, the *top* must also be
    // aligned
    top = aligndown( base+size );
    cyg_uint8 *metatop = metabottom + 
        sizeof(struct memdq)*(metasize/sizeof(struct memdq));
    
    CYG_ASSERT( top > bottom , "heap too small" );
    CYG_ASSERT( top <= (base+size), "top too large" );
    CYG_ASSERT( (((cyg_int32)(top)) & alignment-1)==0,
                "top badly aligned" );
    CYG_ASSERT( (((cyg_int32)(bottom)) & alignment-1)==0,
                "bottom badly aligned" );

    CYG_ASSERT( metatop > metabottom , "meta space too small" );
    CYG_ASSERT( metatop <= (metabase+metasize), "metatop too large" );

    // Initialize list of unused metadata blocks. Only need to do next
    // pointers - can ignore prev and size
    struct memdq *fq = freemetahead = (struct memdq *)metabottom;
    
    while ((cyg_uint8 *)fq < metatop) {
        fq->next = fq+1;
        fq++;
    }

    CYG_ASSERT((cyg_uint8 *)fq == metatop, "traversed metadata not aligned");

    // set final pointer to NULL;
    --fq; fq->next = NULL;

    // initialize the free list. memhead is the initial free block occupying
    // all of free memory.
    memhead.next = memhead.prev = &freehead;
    // The mem list is circular for consistency.
    memhead.memprev = memhead.memnext = &memend;
    memhead.mem = bottom;

    // initialize block that indicates end of memory. This pretends to
    // be an allocated block
    memend.next = memend.prev = &allocedhead;
    memend.memnext = memend.memprev = &memhead;
    memend.mem = top;

    // initialize alloced list memdq. memend pretends to be allocated memory
    // at the end
    allocedhead.next = allocedhead.prev = &memend;

⌨️ 快捷键说明

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