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
bio.c
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 
 All Data Structures