Xv6 with picoc & Linkage editor
v1.0
The project delineate mutual cohesion between c library, linkage editor ( linker), interpreter and operating system by porting the same on xv6 kernel
|
00001 // Buffer cache. 00002 // 00003 // The buffer cache is a linked list of buf structures holding 00004 // cached copies of disk block contents. Caching disk blocks 00005 // in memory reduces the number of disk reads and also provides 00006 // a synchronization point for disk blocks used by multiple processes. 00007 // 00008 // Interface: 00009 // * To get a buffer for a particular disk block, call bread. 00010 // * After changing buffer data, call bwrite to write it to disk. 00011 // * When done with the buffer, call brelse. 00012 // * Do not use the buffer after calling brelse. 00013 // * Only one process at a time can use a buffer, 00014 // so do not keep them longer than necessary. 00015 // 00016 // The implementation uses three state flags internally: 00017 // * B_BUSY: the block has been returned from bread 00018 // and has not been passed back to brelse. 00019 // * B_VALID: the buffer data has been read from the disk. 00020 // * B_DIRTY: the buffer data has been modified 00021 // and needs to be written to disk. 00022 00023 #include "types.h" 00024 #include "defs.h" 00025 #include "param.h" 00026 #include "spinlock.h" 00027 #include "buf.h" 00028 00029 struct { 00030 struct spinlock lock; 00031 struct buf buf[NBUF]; 00032 00033 // Linked list of all buffers, through prev/next. 00034 // head.next is most recently used. 00035 struct buf head; 00036 } bcache; 00037 00038 void 00039 binit(void) 00040 { 00041 struct buf *b; 00042 00043 initlock(&bcache.lock, "bcache"); 00044 00045 //PAGEBREAK! 00046 // Create linked list of buffers 00047 bcache.head.prev = &bcache.head; 00048 bcache.head.next = &bcache.head; 00049 for(b = bcache.buf; b < bcache.buf+NBUF; b++){ 00050 b->next = bcache.head.next; 00051 b->prev = &bcache.head; 00052 b->dev = -1; 00053 bcache.head.next->prev = b; 00054 bcache.head.next = b; 00055 } 00056 } 00057 00058 // Look through buffer cache for sector on device dev. 00059 // If not found, allocate fresh block. 00060 // In either case, return B_BUSY buffer. 00061 static struct buf* 00062 bget(uint dev, uint sector) 00063 { 00064 struct buf *b; 00065 00066 acquire(&bcache.lock); 00067 00068 loop: 00069 // Is the sector already cached? 00070 for(b = bcache.head.next; b != &bcache.head; b = b->next){ 00071 if(b->dev == dev && b->sector == sector){ 00072 if(!(b->flags & B_BUSY)){ 00073 b->flags |= B_BUSY; 00074 release(&bcache.lock); 00075 return b; 00076 } 00077 sleep(b, &bcache.lock); 00078 goto loop; 00079 } 00080 } 00081 00082 // Not cached; recycle some non-busy and clean buffer. 00083 for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ 00084 if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){ 00085 b->dev = dev; 00086 b->sector = sector; 00087 b->flags = B_BUSY; 00088 release(&bcache.lock); 00089 return b; 00090 } 00091 } 00092 panic("bget: no buffers"); 00093 } 00094 00095 // Return a B_BUSY buf with the contents of the indicated disk sector. 00096 struct buf* 00097 bread(uint dev, uint sector) 00098 { 00099 struct buf *b; 00100 00101 b = bget(dev, sector); 00102 if(!(b->flags & B_VALID)) 00103 iderw(b); 00104 return b; 00105 } 00106 00107 // Write b's contents to disk. Must be B_BUSY. 00108 void 00109 bwrite(struct buf *b) 00110 { 00111 if((b->flags & B_BUSY) == 0) 00112 panic("bwrite"); 00113 b->flags |= B_DIRTY; 00114 iderw(b); 00115 } 00116 00117 // Release a B_BUSY buffer. 00118 // Move to the head of the MRU list. 00119 void 00120 brelse(struct buf *b) 00121 { 00122 if((b->flags & B_BUSY) == 0) 00123 panic("brelse"); 00124 00125 acquire(&bcache.lock); 00126 00127 b->next->prev = b->prev; 00128 b->prev->next = b->next; 00129 b->next = bcache.head.next; 00130 b->prev = &bcache.head; 00131 bcache.head.next->prev = b; 00132 bcache.head.next = b; 00133 00134 b->flags &= ~B_BUSY; 00135 wakeup(b); 00136 00137 release(&bcache.lock); 00138 } 00139