/* databuff.c - Buffer management routines */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* |_o_o|\\ Copyright (c) 1988 The Software Distillery. All Rights Reserved */ /* |. o.| || This program may not be distributed without the permission of */ /* | . | || the authors: BBS: (919) 481-6436 */ /* | o | || John Toebes John Mainwaring Jim Cooper */ /* | . |// Bruce Drake Gordon Keener Dave Baker */ /* ====== */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Buffer management routines : */ /* ModBlock GetBlock */ /* FindBuffer AllocBuffers FreeBuffers FlushBuffers FlushOne */ #include "handler.h" char *GetBlock(global, key) GLOBAL global; KEY key; { int i; i = FindBuffer(global, key, 1); if (i == -1) return(NULL); BUG(("GetBlock: Key %ld Buff %08lx\n", key, global->blkbuf[i].bb_blk)); return(global->blkbuf[i].bb_blk); } char *ModBlock(global, key) GLOBAL global; KEY key; { int i; /* Make sure we have the rights to write to the disk */ if (global->diskstate != ID_VALIDATED) { BUG(("ModBlock - Write protected disk\n")); global->pkt->dp_Res1 = DOS_FALSE; global->pkt->dp_Res2 = ERROR_DISK_WRITE_PROTECTED; return(NULL); } /* Locate the block in a buffer */ i = FindBuffer(global, key, 1); /* Gee, it wasn't found, just return an error */ if (i == -1) return(NULL); /* Mark it as having been touched so we flush it later */ global->blkbuf[i].bb_dirty = 1; BUG(("ModBlock: Key %ld Buff %08lx\n", key, global->blkbuf[i].bb_blk)); return(global->blkbuf[i].bb_blk); } int FindBuffer(global, key, readin) register GLOBAL global; KEY key; int readin; { register int i; int num; struct BlockBuffer *tmpglob; /* First pass, go through and see if it is already in a buffer */ for (i = 0; i< global->dskenv.de_numbufs; i++) { if (global->blkbuf[i].bb_key == key && global->blkbuf[i].bb_used) { if (global->blkbuf[i].bb_priority < 0xff) global->blkbuf[i].bb_priority++; return(i); } } /* For some reason it wasn't in a buffer already (imagine that). So we */ /* want to go through and decrement all the priorities of the buffers */ /* and select a candidate for flushing to hold our new block. Note that */ /* an empty buffer is assumed to have a priority of 0 while a buffer in */ /* use will never be decremented below 1 */ tmpglob = &global->blkbuf[0]; num = 0; for (i = 0; i < global->dskenv.de_numbufs; i++) { if (global->blkbuf[i].bb_used && (global->blkbuf[i].bb_priority > 1)) global->blkbuf[i].bb_priority--; if (global->blkbuf[i].bb_priority < tmpglob->bb_priority) { tmpglob = &global->blkbuf[i]; num = i; } } /* Now tmpglob points to our new buffer. Empty it out if necessary */ FlushOne(global, num); /* Mark it for the new buffer that we want to use it as */ tmpglob->bb_used = 1; tmpglob->bb_key = key; tmpglob->bb_priority = global->dskenv.de_numbufs; tmpglob->bb_dirty = 0; /* Hopefully FlushOne reset it but who knows */ /* Did they ask us to read it in? */ if (readin) { if (ReadPhy(global, tmpglob->bb_blk, key)) { BUG(("Failure reading in key %ld\n", key)); tmpglob->bb_used = 0; tmpglob->bb_key = -1; tmpglob->bb_priority = 0; num = -1; /* indicate the failure */ } } return(num); } void FreeBlkBuffs(global) GLOBAL global; { BUG(("FreeBlkBuffs\n")); FreeMem((char *)global->blkbuf,((sizeof(struct BlockBuffer))* (global->dskenv.de_numbufs))); global->blkbuf = NULL; } int AllocBlkBuffs(global, newsize) GLOBAL global; int newsize; { struct BlockBuffer *tmpbuff; int i; BUG(("AllocBlkBuffs size:%ld\n",newsize)); if ((tmpbuff = (struct BlockBuffer *)AllocMem(((sizeof(struct BlockBuffer)) * newsize),(MEMF_PUBLIC | MEMF_CLEAR)))== NULL){ BUG(("AllocBlkBuffs Failed\n")); return(0); } /* successfully allocated copy stuff over and free old */ if (global->blkbuf){ for(i=0;i < (global->dskenv.de_numbufs);i++){ if (i < newsize){ tmpbuff[i].bb_blk = global->blkbuf[i].bb_blk; } if (i >= newsize){ FreeMem(global->blkbuf[i].bb_blk, ((global->dskenv.de_sizeblock) * BYTESPERLONG)); } } FreeBlkBuffs(global); } BUG(("Allocated blk buffs at:%08lx\n",tmpbuff)); /* allocate memory for data blocks */ for(i=0;i < newsize;i++){ if (tmpbuff[i].bb_blk == NULL){ if((tmpbuff[i].bb_blk = (char *) AllocMem(((global->dskenv.de_sizeblock) * BYTESPERLONG), global->dskenv.de_membuftype))==NULL){ /* we will loose some bytes here for now */ global->dskenv.de_numbufs = i; return(NULL); } } tmpbuff[i].bb_key = -1; } global->blkbuf = tmpbuff; global->dskenv.de_numbufs = newsize; return(-1); } void FlushOne(global, num) GLOBAL global; int num; { /* Does this buffer need to be written out to disk ? */ if (global->blkbuf[num].bb_dirty && global->blkbuf[num].bb_used) { /* Ok, see if it needs to be checksummed */ if (global->blkbuf[num].bb_used != ST_BITMAP) DoCheckSum(global, global->blkbuf[num].bb_blk); /* At last we get to write out the block */ while(WritePhy(global, global->blkbuf[num].bb_blk, global->blkbuf[num].bb_key)) { if (!request(global, REQ_ERROR, NULL)) break; ResetDrive(global); } } /* Now we need to reset it so it doesn't get written out again */ global->blkbuf[num].bb_dirty = 0; } void FlushBuffers(global, purge) GLOBAL global; int purge; { register int i; for (i = 0; i < global->dskenv.de_numbufs; i++) { FlushOne(global, i); /* Did they want us to forget about when we are done ? */ if (purge) { /* If we don't want the buffer any more we need to zap it */ global->blkbuf[i].bb_used = 0; global->blkbuf[i].bb_key = -1; global->blkbuf[i].bb_priority = 0; } } }