📄 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_STRINGSstatic 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 TOMvoid 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 + -