📄 blib.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 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 + -