/***********************************************************************\ Filename: memory.c \***********************************************************************/ #include #include "proxlib.h" #include "proxio.h" #include "spmemory.h" #include "scdef.h" #include "sp.h" #include "spdef.h" #ifndef MM_NBLKS #define MM_NBLKS 4 /* Default number of blocks to use */ #endif /* Control structure for each buffer. */ typedef struct mb_struct { HANDLE mb_file; /* file the block came from */ UCHAR *mb_blk; /* block-sized buffer (actual data) */ int mb_blknum; /* block's block number in the file */ UCHAR mb_flags; /* priority and usage requested */ UCHAR mb_age; /* how long block has been in list */ struct mb_struct *mb_newer;/* pointer to newer block */ struct mb_struct *mb_older;/* pointer to older block */ } MEMBLK; int Memup[] = { 0 }; /* Memory is initialized */ static MEMBLK Memlist[MM_NBLKS];/* Memory headers */ static MEMBLK *Memnewest[1]; /* Newest memory block */ /* Initialize the block buffering system. */ meminit() { register MEMBLK *mp; /* If this has already been done, return. */ if (Memup[0]) return(1); /* Allocate space for each memory block; initialize each control structure. */ for (mp = Memlist + MM_NBLKS; --mp >= Memlist; ) { if (!(mp->mb_blk = (char *) zalloc(_SPTHID[0], MM_BLKSIZE))) return(0); mp->mb_file = H_ERROR; mp->mb_flags = 0; mp->mb_newer = mp - 1; mp->mb_older = mp + 1; } /* Make the linked list into a circular queue. */ Memlist[0].mb_newer = &Memlist[MM_NBLKS - 1]; Memlist[MM_NBLKS - 1].mb_older = Memlist; /* Initialize the top of memory pointer. */ Memnewest[0] = Memlist; /* Memory has been initialized */ Memup[0] = 1; return(1); } /* See if a block for a given file is in memory. */ MEMBLK *memcheck(file, blknum) HANDLE file; /* The file the block is in. */ int blknum; /* The block number. */ { register MEMBLK *mp; mp = Memnewest[0]; while (mp->mb_file != file || mp->mb_blknum != blknum) { mp = mp->mb_older; if (mp == Memnewest[0]) return (NULL); } return (mp); } /* Put a buffer at the top of the list. This is the only routine that changes the memory control links. */ void memlink(mp) register MEMBLK *mp; { register MEMBLK *new; /* Do nothing if the buffer is already at the top of the list. */ new = Memnewest[0]; if (new == mp) return; /* Unlink the buffer from the list. */ mp->mb_newer->mb_older = mp->mb_older; mp->mb_older->mb_newer = mp->mb_newer; /* Add it to the top of the list. */ Memnewest[0] = mp; mp->mb_newer = new->mb_newer; mp->mb_older = new; new->mb_newer->mb_older = mp; new->mb_newer = mp; } /* Make a buffer unused. If the buffer contained modified data, write that data to disk. */ memdel(mp) register MEMBLK *mp; { /* Write the block, if it was modified. */ if (!memwrite(mp)) return (FALSE); /* make the buffer unused. */ mp->mb_file = H_ERROR; mp->mb_flags = 0; /* Make this buffer the newest; since the list is circular, moving the newest pointer down to the next oldest will make this block the oldest. */ memlink(mp); Memnewest[0] = (Memnewest[0])->mb_older; return (TRUE); } /* Write a block to disk. */ memwrite(mp) register MEMBLK *mp; { /* Do not write it if it was not modified. */ if (!(mp->mb_flags & MM_WRITE)) return (TRUE); /* Seek to the proper place and then write the buffer. */ if (stdseek((long)mp->mb_blknum * MM_BLKSIZE, mp->mb_file) || stdwrite((char *)mp->mb_blk, MM_BLKSIZE, mp->mb_file) != MM_BLKSIZE) return (FALSE); /* Mark the buffer as no longer modified. */ mp->mb_flags &= ~MM_WRITE; return (TRUE); } /* Get a buffer for a block. */ UCHAR * memread(blknum, file, flags) int blknum; /* Block number in file. */ HANDLE file; /* File to read. */ int flags; /* Read flags. */ { MEMBLK *mp; /* Look for the block in memory. If it is not in memory then read it. */ if ((mp = memcheck(file, blknum)) == NULL) { /* Find a buffer to read into. */ mp = Memnewest[0]; while (1) { mp = mp->mb_newer; if (mp == Memnewest[0]) { mp = mp->mb_newer; break; } if (mp->mb_age >= (flags & MM_PRMASK)) break; } /* Free the buffer. */ if (!memdel(mp)) return (NULL); /* if MM_READ was specified, read the block from the file */ if (flags & MM_READ) { if (stdseek((long)blknum * MM_BLKSIZE, file) || stdread((char *) mp->mb_blk, MM_BLKSIZE, file) != MM_BLKSIZE) return (NULL); } /* Initialize the memory data. */ mp->mb_file = file; mp->mb_blknum = blknum; mp->mb_flags = flags; } else /* Make this block the newest; update its modify flag; store its priority and return the block. */ mp->mb_flags |= flags & MM_WRITE; mp->mb_age = flags & MM_PRMASK; memlink(mp); return (mp->mb_blk); } /* If file is NULLPTR write all modified blocks to disk. If not, release all memory associated with the file. */ memflush(file) HANDLE file; /* The file to flush. */ { MEMBLK *mp; for (mp = Memlist + MM_NBLKS; --mp >= Memlist; ) { if (!file) { if (!memwrite(mp)) return (ERROR); } else if (mp->mb_file == file && !memdel(mp)) return (ERROR); } return (OKAY); } /* Change the block number associated with a block already in memory. */ int memswitch(file, oldnum, newnum) HANDLE file; /* The file to do it to. */ int oldnum; /* The old block number */ int newnum; /* The new block number */ { register MEMBLK *mp; if ((mp = memcheck(file, oldnum)) == NULL) { return (FALSE); } mp->mb_blknum = newnum; return (TRUE); }