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

📄 block.c

📁 嵌入式操作系统Nucleus Plus中使用的文件系统
💻 C
字号:
/*
* EBS - RTFS (Real Time File Manager)
*
* Copyright Peter Van Oudenaren , 1993
* All rights reserved.
* This code may not be redistributed in source or linkable object form
* without the consent of its author.
*/
/* BLOCK.C - Directory block buffering routines
    
    Block buffers contain a data block a DDRIVE pointer and a block number.
    If the DDRIVE pointer is Non Null the data is valid for the block.
    Blocks have three states.
        Unused - May be grabbed to use on a block. (PDRIVE == NULL)
        Locked - May not be re-used until the routine using it lets go
        Unlocked- Data is valid in the buffer but no one is using it. 
                  if there are no Unused blocks this one may be used.
                  But if someone needs the data in here it will be relocked
                  and used.            

    Routines in this file include:

    pc_alloc_blk    -   Internal to this file. 
    pc_blkpool      -   Internal to this file. 
    pc_free_all_blk -   Release all buffers associated with a drive
    pc_free_buf     -   Release a single buffer for possible re-use

    pc_init_blk     -   Initialize a buffer's drive and block #s. Zero its
                        data buffer
    pc_read_blk     -   Read data from disk into a buffer
    pc_write_blk    -   Write data from the buffer to the disk.
*/

#include "pcdisk.h"

IMPORT BLKBUFF *mem_block_pool;
IMPORT _PC_BDEVSW pc_bdevsw[];

/******************************************************************************
    PC_ALLOC_BLK - Find existing or create an empty block in the buffer pool.

Description
    Use pdrive and blockno to search for a buffer in the buffer pool.
    If not found create a new buffer entry by discarding the Least recently
    used buffer in the buffer pool. The buffer is locked in core. A pointer to
    the buffer is returned in ppblk. If all buffers are in use it returns 
    NULL in *ppblk.

 Returns
    Returns YES if the buffer was found in the pool or NO if a new
    buffer was assigned.
*****************************************************************************/

/* This function is used only by functions in this file */
BOOL pc_alloc_blk(BLKBUFF **ppblk, DDRIVE *pdrive, BLOCKT blockno)   /*__fn__*/
{
    BLKBUFF *pblk;
    BLKBUFF *oldest = NULL;
    BLKBUFF *freeblk = NULL;
    ULONG lru = (ULONG) ~0L;
    LOCAL ULONG  useindex = 0L;

    /* Get or init the block pool */
    pblk = pc_blkpool(pdrive); 

    useindex += 1;
    while (pblk)
    {
        if (!pblk->pdrive)
        {
          /* This buffer's free */
            freeblk = pblk;            /* BUG FIX */
        }
        else
        {
            if ( (pblk->pdrive == pdrive) && (pblk->blockno == blockno)  )
            {
                /* Found it */
                *ppblk = pblk;
                /* Update the last recently used stuf */
                pblk->lru = useindex;
                pblk->use_count += 1;
                return(YES);
            }
            else
            {
                /* No match. see if its a candidate for swapping if we run out of
                   pointers */
                if (!pblk->use_count)
                {
                    if (pblk->lru < lru)
                    {
                        lru = pblk->lru;
                        oldest = pblk;
                    }
                }
            }
        }
        pblk = pblk->pnext;
    }

    /* If off the end of the list we have to bump somebody */
    if (freeblk)
        pblk = freeblk;
    else
        pblk = oldest;

    if (!pblk)
    {
        pc_report_error(PCERR_BLOCKCLAIM);
        /* Panic */
        *ppblk = NULL;
        return(NO);
    }

    pblk->lru = useindex;
    pblk->pdrive = pdrive;
    pblk->blockno = blockno;
    pblk->use_count = 1;
    pblk->io_pending = NO;
    pblk->io_error = NO;

    *ppblk = pblk;
    
    /* Return NO since we didn't find it in the buffer pool */
    return (NO);
}
 
/****************************************************************************
    PC_BLKBOOL - Return the first element in a drives buffer pool

Description
    Return the beginning of the buffer pool for a drive. If the pool
    is uninitialized report it. The buffer pool should have been 
    initialized in pc_memory_init.

 Returns
    Returns the beginning of the buffer pool or NULL if pc_memory_init was
    not first called.

****************************************************************************/

/* Return the beginning of the buffer pool. Report an error if not already 
   initialized */
BLKBUFF *pc_blkpool(DDRIVE *pdrive)                                 /*__fn__*/
{
    pdrive = pdrive;                /* Make compilers happy */
    /* If not initialized somebody didn't call pc_meminit */
    if (!mem_block_pool)
        pc_report_error(PCERR_BLOCKALLOC);
    return(mem_block_pool);
}

/****************************************************************************
    PC_FREE_ALL_BLK - Release all buffers associated with a drive

Description
    Use pdrive to find all buffers in the buffer pool associated with the
    drive. Mark them as unused, called by dsk_close.
    If any are locked, print a debug message in debug mode to warn the
    programmer.

 Returns
    Nothing
****************************************************************************/
 
VOID pc_free_all_blk(DDRIVE *pdrive)                                /*__fn__*/
{
     BLKBUFF *pblk;

    /* Get or init the block pool */
    pblk = pc_blkpool(pdrive); 

    while (pblk)
    {
        if (pblk->pdrive == pdrive)
        {
            if (pblk->use_count)
                pc_report_error(PCERR_BLOCKLOCK);
            pc_free_buf(pblk, YES);
        }
        pblk = pblk->pnext;
    }
}

/*****************************************************************************
    PC_FREE_BUF - Unlock a block buffer.

Description
    Give back a buffer to the system buffer pool so that it may
    be re-used. If was_err is YES this means that the data in the 
    buffer is invalid so discard the buffer from the buffer pool.

    
 Returns
    Nothing

***************************************************************************/

/* Free a buffer by unlocking it. If waserr is true, zero out the  
    drive number so the erroneous data is not cached. */
VOID pc_free_buf(BLKBUFF *pblk, BOOL    waserr)                      /*__fn__*/
{

    if (pblk)
    {
        if (pblk->use_count)
            pblk->use_count -= 1;
        /* If the buffer is corrupted we null the buffer. This is safe even
           in a multitasking environment because the region of the disk
           containing the block is always locked exclusively when buffer
           writes are taking place */
        if (waserr)
            pblk->pdrive = NULL;
    }
}


/***************************************************************************
    PC_INIT_BLK - Zero a BLKBUFF and add it to the buffer pool
Description
    Allocate and zero a BLKBUFF and add it to the to the buffer pool.

    Note: After initializing you "own" the buffer. You must release it by
    calling pc_free_buff() before it may be used for other blocks.

 Returns
    Returns a valid pointer or NULL if no core.

****************************************************************************/

BLKBUFF *pc_init_blk(DDRIVE *pdrive, BLOCKT blockno)                /*__fn__*/
{
    BLKBUFF *pblk;

    if ( !pdrive || (blockno >= pdrive->numsecs) )
        return(NULL);
    else
    {
        pc_alloc_blk(&pblk, pdrive , blockno );
        if (!pblk)
            return(NULL);
        pc_memfill(pblk->data, 512, '\0');
        return (pblk);
    }
}

/****************************************************************************
    PC_READ_BLK - Allocate and read a BLKBUFF, or get it from the buffer pool.

Description
    Use pdrive and blockno to determine what block to read. Read the block
    or get it from the buffer pool and return the buffer.

    Note: After reading, you "own" the buffer. You must release it by
    calling pc_free_buff() before it may be used for other blocks.

 Returns
    Returns a valid pointer or NULL if block not found and not readable.

*****************************************************************************/

BLKBUFF *pc_read_blk(DDRIVE *pdrive, BLOCKT blockno)                /*__fn__*/
{
    BLKBUFF *pblk;
    BOOL found_buffer;

    if ( !pdrive || (blockno >= pdrive->numsecs) )
        return(NULL);

    found_buffer = pc_alloc_blk(&pblk, pdrive , blockno);
    if (!pblk)
        return(NULL);       /* Internal error */

    if (found_buffer)
    {

        /* If the block is being read we loop until the io_pending
           condition is gone. */
#if (LOCK_METHOD == 2)
        while (pblk->io_pending)
        {
            fs_release();
            fs_suspend_task();
            fs_reclaim();
        }
#endif
        /* If the error flag is set in the block we return error. If we're the
           last one to sense the error we free the buffer */
        if (pblk->io_error)
        {
            pblk->use_count -= 1;
            if (!pblk->use_count)
            {
                /* If we are the last request null out the buffer */
                pblk->pdrive = NULL;
            }
            pblk = NULL;
        }
    }
    else
    {
        /* Not found. Read it in */
        pblk->io_pending = YES;
        pblk->io_error = NO;
        PC_DRIVE_IO_ENTER(pdrive->driveno)
        if (!pc_bdevsw[pdrive->driveno].io_proc(pdrive->driveno, blockno, pblk->data, (COUNT) 1, YES))
        {
            /* oops: Drop the use count and mark an error.
                     if anybody else is waiting do a wakeup */
            pblk->io_pending =  NO;
            pblk->use_count -=  1;
            pblk->io_error   =  YES;
            if (!pblk->use_count)
                pblk->pdrive = NULL;    /* Now the block doesn't exist
                                           in the buffer pool */
            pblk = NULL;
        }
        else
        {
            /* The read worked */
            pblk->io_pending = NO;
        }
        PC_DRIVE_IO_EXIT(pdrive->driveno)
    }
    return (pblk);
}

/***************************************************************************
    PC_WRITE_BLK - Flush a BLKBUFF to disk.
Description
    Use pdrive and blockno information in pblk to flush it's data buffer
    to disk.

 Returns
    Returns YES if the write succeeded.
****************************************************************************/

/* Write */
BOOL pc_write_blk(BLKBUFF *pblk)                                    /*__fn__*/
{
    BOOL ret_val;

    if (!pblk || !pblk->pdrive)
        return(NO);
    PC_DRIVE_IO_ENTER(pblk->pdrive->driveno)
    ret_val = pc_bdevsw[pblk->pdrive->driveno].io_proc(pblk->pdrive->driveno,pblk->blockno, pblk->data, (COUNT) 1, NO);
    PC_DRIVE_IO_EXIT(pblk->pdrive->driveno)
    return(ret_val);
}

⌨️ 快捷键说明

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