📄 blockio.c
字号:
/****************************************************************/
/* */
/* blockio.c */
/* DOS-C */
/* */
/* Block cache functions and device driver interface */
/* */
/* Copyright (c) 1995 */
/* Pasquale J. Villani */
/* All Rights Reserved */
/* */
/* This file is part of DOS-C. */
/* */
/* DOS-C 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. */
/* */
/* DOS-C 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 DOS-C; see the file COPYING. If not, */
/* write to the Free Software Foundation, 675 Mass Ave, */
/* Cambridge, MA 02139, USA. */
/* */
/****************************************************************/
#include "portab.h"
#include "globals.h"
#ifdef VERSION_STRINGS
static BYTE *blockioRcsId =
"$Id: blockio.c,v 1.31 2004/04/20 18:43:03 bartoldeman Exp $";
#endif
#define b_next(bp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), bp->b_next)))
#define b_prev(bp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), bp->b_prev)))
#define bufptr(fbp) ((struct buffer FAR *)(MK_FP(FP_SEG(bp), fbp)))
/************************************************************************/
/* */
/* block cache routines */
/* */
/************************************************************************/
/* #define DISPLAY_GETBLOCK */
STATIC BOOL flush1(struct buffer FAR * bp);
/*
this searches the buffer list for the given disk/block.
returns:
a far pointer to the buffer.
If the buffer is found the UNCACHE bit is not set and else it is set.
new:
upper layer may set UNCACHE attribute
UNCACHE buffers are recycled first.
intended to be used for full sector reads into application buffer
resets UNCACHE upon a "HIT" -- so then this buffer will not be
recycled anymore.
*/
STATIC void move_buffer(struct buffer FAR *bp, size_t firstbp)
{
/* connect bp->b_prev and bp->b_next */
b_next(bp)->b_prev = bp->b_prev;
b_prev(bp)->b_next = bp->b_next;
/* insert bp between firstbp and firstbp->b_prev */
bp->b_prev = bufptr(firstbp)->b_prev;
bp->b_next = firstbp;
b_next(bp)->b_prev = FP_OFF(bp);
b_prev(bp)->b_next = FP_OFF(bp);
}
STATIC struct buffer FAR *searchblock(ULONG blkno, COUNT dsk)
{
int fat_count = 0;
struct buffer FAR *bp;
size_t lastNonFat = 0;
size_t uncacheBuf = 0;
seg bufseg = FP_SEG(firstbuf);
size_t firstbp = FP_OFF(firstbuf);
#ifdef DISPLAY_GETBLOCK
printf("[searchblock %d, blk %ld, buf ", dsk, blkno);
#endif
/* Search through buffers to see if the required block */
/* is already in a buffer */
bp = MK_FP(bufseg, firstbp);
do
{
if ((bp->b_blkno == blkno) &&
(bp->b_flag & BFR_VALID) && (bp->b_unit == dsk))
{
/* found it -- rearrange LRU links */
#ifdef DISPLAY_GETBLOCK
printf("HIT %04x:%04x]\n", FP_SEG(bp), FP_OFF(bp));
#endif
bp->b_flag &= ~BFR_UNCACHE; /* reset uncache attribute */
if (FP_OFF(bp) != firstbp)
{
*(UWORD *)&firstbuf = FP_OFF(bp);
move_buffer(bp, firstbp);
}
return bp;
}
if (bp->b_flag & BFR_UNCACHE)
uncacheBuf = FP_OFF(bp);
if (bp->b_flag & BFR_FAT)
fat_count++;
else
lastNonFat = FP_OFF(bp);
bp = b_next(bp);
} while (FP_OFF(bp) != firstbp);
/*
now take either the last buffer in chain (not used recently)
or, if we are low on FAT buffers, the last non FAT buffer
*/
if (uncacheBuf)
{
bp = bufptr(uncacheBuf);
}
else if (bp->b_flag & BFR_FAT && fat_count < 3 && lastNonFat)
{
bp = bufptr(lastNonFat);
}
else
{
bp = b_prev(bufptr(firstbp));
}
bp->b_flag |= BFR_UNCACHE; /* set uncache attribute */
#ifdef DISPLAY_GETBLOCK
printf("MISS, replace %04x:%04x]\n", FP_SEG(bp), FP_OFF(bp));
#endif
if (FP_OFF(bp) != firstbp) /* move to front */
{
move_buffer(bp, firstbp);
*(UWORD *)&firstbuf = FP_OFF(bp);
}
return bp;
}
BOOL DeleteBlockInBufferCache(ULONG blknolow, ULONG blknohigh, COUNT dsk, int mode)
{
struct buffer FAR *bp = firstbuf;
/* Search through buffers to see if the required block */
/* is already in a buffer */
do
{
if (blknolow <= bp->b_blkno &&
bp->b_blkno <= blknohigh &&
(bp->b_flag & BFR_VALID) && (bp->b_unit == dsk))
{
if (mode == XFR_READ)
flush1(bp);
else
bp->b_flag = 0;
}
bp = b_next(bp);
}
while (FP_OFF(bp) != FP_OFF(firstbuf));
return FALSE;
}
#if TOM
void dumpBufferCache(void)
{
struct buffer FAR *bp = firstbuf;
int printed = 0;
/* Search through buffers to see if the required block */
/* is already in a buffer */
do
{
printf("%8lx %02x ", bp->b_blkno, bp->b_flag);
if (++printed % 6 == 0)
printf("\n");
bp = b_next(bp);
}
while (FP_OFF(bp) != FP_OFF(firstbuf));
printf("\n");
}
#endif
/* */
/* Return the address of a buffer structure containing the */
/* requested block. */
/* if overwrite is set, then no need to read first */
/* */
/* returns: */
/* requested block with data */
/* failure: */
/* returns NULL */
/* */
struct buffer FAR *getblk(ULONG blkno, COUNT dsk, BOOL overwrite)
{
/* Search through buffers to see if the required block */
/* is already in a buffer */
struct buffer FAR *bp = searchblock(blkno, dsk);
if (!(bp->b_flag & BFR_UNCACHE))
{
return bp;
}
/* The block we need is not in a buffer, we must make a buffer */
/* available, and fill it with the desired block */
/* take the buffer that lbp points to and flush it, then read new block. */
if (!flush1(bp))
return NULL;
/* Fill the indicated disk buffer with the current track and sector */
if (!overwrite && dskxfer(dsk, blkno, bp->b_buffer, 1, DSKREAD))
{
return NULL;
}
bp->b_flag = BFR_VALID | BFR_DATA;
bp->b_unit = dsk;
bp->b_blkno = blkno;
return bp;
}
/* */
/* Mark all buffers for a disk as not valid */
/* */
VOID setinvld(REG COUNT dsk)
{
struct buffer FAR *bp = firstbuf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -