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

📄 blib.c

📁 eCos操作系统源码
💻 C
字号:
//==========================================================================////      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 voidrb_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__ voidrb_del_block(cyg_blib_t *bl, blib_block_t *block){    rb_erase(&block->rb_node, &bl->rb_root);}// --------------------------------------------------------------------static __inline__ voidlist_add_block(cyg_blib_t *bl, blib_block_t *block){    list_add(&block->list_node, &bl->list_head);}static __inline__ voidlist_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 voidlist_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_uint32get_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);            return ret;        }    }    rb_add_block(bl, block);    list_add_block(bl, block);        *dblock = block;    return ret;}static int blib_free_cache(cyg_blib_t *bl){    int ret = ENOERR;    ret = blib_sync(bl);    if (ENOERR == ret)        cyg_mempool_fix_delete(bl->mem_pool_h);    return ret;}static intblib_init_cache(cyg_blib_t *bl,                 void       *mem_base,                cyg_uint32  mem_size,                cyg_uint32  block_size,                 cyg_bool    reinit){    int ret = ENOERR;    cyg_uint32 mem_block_size;        if (reinit)    {        ret = blib_free_cache(bl);         if (ENOERR != ret)            return ret;    }        bl->rb_root = RB_ROOT;    INIT_LIST_HEAD(&bl->list_head);    bl->mem_base   = mem_base;    bl->mem_size   = mem_size;        bl->block_size = block_size;    bl->block_size_log2 = get_val_log2(block_size);    if (0 == bl->block_size_log2)        return -EINVAL;        mem_block_size = bl->block_size + sizeof(blib_block_t);    cyg_mempool_fix_create(bl->mem_base, bl->mem_size, mem_block_size,                           &bl->mem_pool_h, &bl->mem_pool);    STAT_INIT(bl);    return ret;}// --------------------------------------------------------------------static intio_bread(void *priv, void *buf, cyg_uint32 *len, cyg_uint32 pos){    return cyg_io_bread((cyg_io_handle_t)priv, buf, len, pos);}static intio_bwrite(void *priv, const void *buf, cyg_uint32 *len, cyg_uint32 pos){    return cyg_io_bwrite((cyg_io_handle_t)priv, buf, len, pos);}// --------------------------------------------------------------------intcyg_blib_create(void               *priv_data,                void               *mem_base,                cyg_uint32          mem_size,                cyg_uint32          block_size,                cyg_blib_bread_fn   bread_fn,                cyg_blib_bwrite_fn  bwrite_fn,                cyg_blib_t         *bl){    int ret;        bl->priv      = priv_data;    bl->bread_fn  = bread_fn;    bl->bwrite_fn = bwrite_fn;    ret = blib_init_cache(bl, mem_base, mem_size, block_size, false);     return ret; }int cyg_blib_io_create(cyg_io_handle_t     handle,                   void               *mem_base,                   cyg_uint32          mem_size,                   cyg_uint32          block_size,                   cyg_blib_t         *bl){    return cyg_blib_create((void *)handle, mem_base, mem_size, block_size,                           io_bread, io_bwrite, bl);}intcyg_blib_delete(cyg_blib_t *bl){    return blib_free_cache(bl);}int cyg_blib_bread(cyg_blib_t *bl,               void       *buf,               cyg_uint32 *len,               cyg_uint32  pos){    blib_block_t *block;    cyg_int32  size = *len;    cyg_int32  bnum = pos;    cyg_uint8 *bbuf = buf;    Cyg_ErrNo  ret  = ENOERR;    D(("blib bread block=%d len=%d buf=%p\n", pos, *len, buf));     while (size > 0)    {        ret = blib_get_block(bl, bnum, true, &block);         if (ENOERR != ret)            break;                memcpy((void *)bbuf, (void *)block->data, bl->block_size);        bbuf += bl->block_size;        bnum++;        size--;    }    *len -= size;    return ret;}int cyg_blib_bwrite(cyg_blib_t *bl,                const void *buf,                cyg_uint32 *len,                cyg_uint32  pos){    blib_block_t *block;    cyg_int32  size = *len;    cyg_int32  bnum = pos;    cyg_uint8 *bbuf = (cyg_uint8 * const) buf;    Cyg_ErrNo  ret  = ENOERR;    D(("blib bwrite block=%d len=%d buf=%p\n", pos, *len, buf));     while (size > 0)    {        ret = blib_get_block(bl, bnum, false, &block);         if (ENOERR != ret)            break;                memcpy((void *)block->data, (void *)bbuf, bl->block_size);        block->modified = true;        bbuf += bl->block_size;        bnum++;        size--;    }    *len -= size;    return ret;}intcyg_blib_read(cyg_blib_t *bl,              void       *buf,              cyg_uint32 *len,              cyg_uint32  bnum,              cyg_uint32  pos){    blib_block_t *block;    cyg_uint8 *bbuf = buf;    cyg_int32  size = *len;    Cyg_ErrNo  ret  = ENOERR;    size = *len;    if (pos >= bl->block_size)    {        bnum += pos >> bl->block_size_log2;        pos   = pos & (bl->block_size - 1);    }            D(("blib read len=%d pos=%d bnum=%d\n", *len, pos, bnum));    while (size > 0)    {        int csize;        if ((size + pos) > bl->block_size)            csize = bl->block_size - pos;        else            csize = size;        ret = blib_get_block(bl, bnum, true, &block);        if (ENOERR != ret)            break;         memcpy((void *)bbuf, (void *)(block->data+pos), csize);        bbuf += csize;        size -= csize;        pos   = 0;        bnum++;    }    *len -= size;    return ret;}intcyg_blib_write(cyg_blib_t *bl,               const void *buf,               cyg_uint32 *len,               cyg_uint32  bnum,               cyg_uint32  pos){    blib_block_t *block;    cyg_uint8 *bbuf = (cyg_uint8 * const) buf;    cyg_int32  size = *len;    Cyg_ErrNo  ret  = ENOERR;    size = *len;    if (pos >= bl->block_size)    {        bnum += pos >> bl->block_size_log2;        pos   = pos & (bl->block_size - 1);    }            D(("blib write len=%d pos=%d bnum=%d\n", *len, pos, bnum));    while (size > 0)    {        int csize;        if ((size + pos) > bl->block_size)            csize = bl->block_size - pos;        else            csize = size;        if (0 == pos && csize == bl->block_size)            ret = blib_get_block(bl, bnum, false, &block);        else            ret = blib_get_block(bl, bnum, true, &block);        if (ENOERR != ret)            break;        memcpy((void *)(block->data+pos), (void *)bbuf, csize);        block->modified = true;        bbuf += csize;        size -= csize;        pos   = 0;        bnum++;    }    *len -= size;    return ret;}intcyg_blib_sync(cyg_blib_t *bl){    return blib_sync(bl);}intcyg_blib_sync_block(cyg_blib_t *bl, cyg_uint32 num){    blib_block_t *block = rb_find_block(bl, num);        if (NULL != block)        return blib_sync_block(bl, block);    else        return -EINVAL;}intcyg_blib_flush(cyg_blib_t *bl){    return blib_init_cache(bl, bl->mem_base,  bl->mem_size,                           bl->block_size, true);}intcyg_blib_set_block_size(cyg_blib_t *bl, cyg_uint32 block_size){    return blib_init_cache(bl, bl->mem_base, bl->mem_size,                            block_size, true); }    intcyg_blib_get_stat(cyg_blib_t *bl, cyg_blib_stat_t *stat){#ifdef CYGIMP_BLOCK_LIB_STATISTICS    *stat = bl->stat;    return ENOERR;#else    stat->n_gets   = 0;    stat->n_reads  = 0;    stat->n_writes = 0;    return -EINVAL;#endif}// --------------------------------------------------------------------// EOF blib.c

⌨️ 快捷键说明

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