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

📄 blib.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      blib.c
//
//      Block cache and access library  
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2003 Savin Zlobec 
//
// 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.
//
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):     savin 
// Date:          2003-08-29
// Description: 
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <cyg/io/io.h>
#include <cyg/infra/cyg_ass.h>      // assertion support
#include <cyg/infra/diag.h>         // diagnostic output
#include <cyg/kernel/kapi.h>
#include <blib/blib.h>

#include <string.h>

#include <linux/rbtree.h>
#include <linux/list.h>

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

//#define DEBUG 1

#ifdef DEBUG
# define D(_args_) diag_printf _args_
#else
# define D(_args_) CYG_EMPTY_STATEMENT
#endif

#ifdef CYGIMP_BLOCK_LIB_STATISTICS

#define STAT_INIT(_bl_) do {    \        bl->stat.n_gets   = 0;  \        bl->stat.n_reads  = 0;  \        bl->stat.n_writes = 0;  \    } while (0)    

#define STAT(_bl_, _group_) \    ((_bl_)->stat._group_++)

#else // CYGIMP_BLOCK_LIB_STATISTICS

#define STAT_INIT(_bl_)     CYG_EMPTY_STATEMENT
#define STAT(_bl_, _group_) CYG_EMPTY_STATEMENT
    
#endif // not CYGIMP_BLOCK_LIB_STATISTICS
 
// --------------------------------------------------------------------

typedef struct {
    struct list_head  list_node; // list node
    struct rb_node    rb_node;   // red-black tree node
    cyg_uint32        num;       // block number
    cyg_bool          modified;  // is this block data modified (needs write)
    cyg_uint8         data[0];   // block data
} blib_block_t;

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

static blib_block_t *
rb_find_block(cyg_blib_t *bl, cyg_uint32 num)
{
    struct rb_node *node  = bl->rb_root.rb_node;
    blib_block_t   *block = NULL;
    
    while (NULL != node)
    {
        block = rb_entry(node, blib_block_t, rb_node);

        if (block->num == num)
            return block;

        node = (block->num > num) ? node->rb_left : node->rb_right;
    }
    return NULL;
}

static void
rb_add_block(cyg_blib_t *bl, blib_block_t *block)
{
    struct rb_node *node = bl->rb_root.rb_node;    

    if (NULL == node)
    {
        rb_link_node(&block->rb_node, NULL, &bl->rb_root.rb_node);
    }
    else
    {
        struct rb_node **link;
        blib_block_t    *b = NULL;
        
        while (NULL != node)
        {
            b = rb_entry(node, blib_block_t, rb_node);

            CYG_ASSERTC(b->num != block->num);

            link = (b->num > block->num) ? &node->rb_left : &node->rb_right;
            node = *link;
        }
        rb_link_node(&block->rb_node, &b->rb_node, link);
    }
    rb_insert_color(&block->rb_node, &bl->rb_root);
}

static __inline__ void
rb_del_block(cyg_blib_t *bl, blib_block_t *block)
{
    rb_erase(&block->rb_node, &bl->rb_root);
}

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

static __inline__ void
list_add_block(cyg_blib_t *bl, blib_block_t *block)
{
    list_add(&block->list_node, &bl->list_head);
}

static __inline__ void
list_del_block(cyg_blib_t *bl, blib_block_t *block)
{
    list_del(&block->list_node);
}

static __inline__ blib_block_t *
list_get_first_block(cyg_blib_t *bl)
{
    return(list_entry(bl->list_head.next, blib_block_t, list_node));
}

static __inline__ blib_block_t *
list_get_last_block(cyg_blib_t *bl)
{
    return(list_entry(bl->list_head.prev, blib_block_t, list_node));
}

static void
list_move_block_to_head(cyg_blib_t *bl, blib_block_t *block)
{
    list_del(&block->list_node);
    list_add(&block->list_node, &bl->list_head);
}

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

static cyg_uint32
get_val_log2(cyg_uint32 val)
{
    cyg_uint32 i, log2;

    i = val;
    log2 = 0;
    while (0 == (i & 1))
    {
        i >>= 1;
        log2++;
    }
    if (i != 1)
        return 0;
    else
        return log2;
}

static int 
blib_sync_block(cyg_blib_t *bl, blib_block_t *block)
{
    int ret = ENOERR;

    if (block->modified)
    {
        int len = 1;

        D(("blib writting block=%d\n", block->num)); 
 
        STAT(bl, n_writes);

        ret = bl->bwrite_fn(bl->priv, (void *)block->data, &len, block->num);

        if (ENOERR == ret)
            block->modified = false;
    }
    return ret;
}

static int 
blib_sync(cyg_blib_t *bl)
{
    struct list_head *node = bl->list_head.next;
    blib_block_t     *block;
    int ret = ENOERR;
 
    D(("blib cache sync\n")); 
    
    while (node != &bl->list_head)
    {
        block = list_entry(node, blib_block_t, list_node);

        ret = blib_sync_block(bl, block);
        if (ENOERR != ret)
           break;
        
        node = node->next;
    }
    return ret;
}

static int 
blib_get_block(cyg_blib_t    *bl, 
               cyg_uint32     num, 
               cyg_bool       read_data,
               blib_block_t **dblock)
{
    blib_block_t *block = NULL;
    int ret = ENOERR;
    int len;
 
    D(("blib get block=%d\n", num)); 
    
    STAT(bl, n_gets);

    // first check if the most recently used block is the requested block,
    // this can improve performance when using byte access functions
    if (!list_empty(&bl->list_head))
    {
        blib_block_t *first_block = list_get_first_block(bl);
        if (first_block->num == num)
            block = first_block;
        else 
            block = rb_find_block(bl, num);
    }
    
    if (NULL != block)
    {
        D(("blib block=%d found in cache\n", num)); 

        list_move_block_to_head(bl, block);
        *dblock = block;
        return ret;
    }

    D(("blib block=%d NOT found in cache\n", num)); 

    block = (blib_block_t *)cyg_mempool_fix_try_alloc(bl->mem_pool_h);

    if (NULL == block)
    {
        CYG_ASSERTC(!list_empty(&bl->list_head));
        
        block = list_get_last_block(bl);

        D(("blib reusing block=%d space\n", block->num)); 

        ret = blib_sync_block(bl, block);
        if (ENOERR != ret)
            return ret;
        
        list_del_block(bl, block);
        rb_del_block(bl, block);
    }

    block->num      = num;
    block->modified = false;

    if (read_data)
    {
        D(("blib reading block=%d\n", block->num)); 

        STAT(bl, n_reads);

        len = 1;
        ret = bl->bread_fn(bl->priv, (void *)block->data, &len, block->num);
        if (ENOERR != ret)
        {
            cyg_mempool_fix_free(bl->mem_pool_h, block);

⌨️ 快捷键说明

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