Straight replacement of B_BUSY with a sleeping lock.
This commit is contained in:
		
							parent
							
								
									551c2f3576
								
							
						
					
					
						commit
						6670d3b5e0
					
				
					 8 changed files with 45 additions and 21 deletions
				
			
		
							
								
								
									
										1
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -15,6 +15,7 @@ OBJS = \ | ||||||
| 	picirq.o\
 | 	picirq.o\
 | ||||||
| 	pipe.o\
 | 	pipe.o\
 | ||||||
| 	proc.o\
 | 	proc.o\
 | ||||||
|  | 	sleeplock.o\
 | ||||||
| 	spinlock.o\
 | 	spinlock.o\
 | ||||||
| 	string.o\
 | 	string.o\
 | ||||||
| 	swtch.o\
 | 	swtch.o\
 | ||||||
|  |  | ||||||
							
								
								
									
										37
									
								
								bio.c
									
										
									
									
									
								
							
							
						
						
									
										37
									
								
								bio.c
									
										
									
									
									
								
							|  | @ -13,9 +13,7 @@ | ||||||
| // * Only one process at a time can use a buffer,
 | // * Only one process at a time can use a buffer,
 | ||||||
| //     so do not keep them longer than necessary.
 | //     so do not keep them longer than necessary.
 | ||||||
| //
 | //
 | ||||||
| // The implementation uses three state flags internally:
 | // The implementation uses two state flags internally:
 | ||||||
| // * B_BUSY: the block has been returned from bread
 |  | ||||||
| //     and has not been passed back to brelse.
 |  | ||||||
| // * B_VALID: the buffer data has been read from the disk.
 | // * B_VALID: the buffer data has been read from the disk.
 | ||||||
| // * B_DIRTY: the buffer data has been modified
 | // * B_DIRTY: the buffer data has been modified
 | ||||||
| //     and needs to be written to disk.
 | //     and needs to be written to disk.
 | ||||||
|  | @ -24,6 +22,7 @@ | ||||||
| #include "defs.h" | #include "defs.h" | ||||||
| #include "param.h" | #include "param.h" | ||||||
| #include "spinlock.h" | #include "spinlock.h" | ||||||
|  | #include "sleeplock.h" | ||||||
| #include "fs.h" | #include "fs.h" | ||||||
| #include "buf.h" | #include "buf.h" | ||||||
| 
 | 
 | ||||||
|  | @ -51,6 +50,7 @@ binit(void) | ||||||
|     b->next = bcache.head.next; |     b->next = bcache.head.next; | ||||||
|     b->prev = &bcache.head; |     b->prev = &bcache.head; | ||||||
|     b->dev = -1; |     b->dev = -1; | ||||||
|  |     initsleeplock(&b->lock, "buffer"); | ||||||
|     bcache.head.next->prev = b; |     bcache.head.next->prev = b; | ||||||
|     bcache.head.next = b; |     bcache.head.next = b; | ||||||
|   } |   } | ||||||
|  | @ -58,7 +58,7 @@ binit(void) | ||||||
| 
 | 
 | ||||||
| // Look through buffer cache for block on device dev.
 | // Look through buffer cache for block on device dev.
 | ||||||
| // If not found, allocate a buffer.
 | // If not found, allocate a buffer.
 | ||||||
| // In either case, return B_BUSY buffer.
 | // In either case, return locked buffer.
 | ||||||
| static struct buf* | static struct buf* | ||||||
| bget(uint dev, uint blockno) | bget(uint dev, uint blockno) | ||||||
| { | { | ||||||
|  | @ -66,12 +66,14 @@ bget(uint dev, uint blockno) | ||||||
| 
 | 
 | ||||||
|   acquire(&bcache.lock); |   acquire(&bcache.lock); | ||||||
| 
 | 
 | ||||||
|  |   //cprintf("bget %d\n", blockno);
 | ||||||
|  loop: |  loop: | ||||||
|   // Is the block already cached?
 |   // Is the block already cached?
 | ||||||
|   for(b = bcache.head.next; b != &bcache.head; b = b->next){ |   for(b = bcache.head.next; b != &bcache.head; b = b->next){ | ||||||
|     if(b->dev == dev && b->blockno == blockno){ |     if(b->dev == dev && b->blockno == blockno){ | ||||||
|       if(!(b->flags & B_BUSY)){ |       if(!holdingsleep(&b->lock)) { | ||||||
|         b->flags |= B_BUSY; |         acquiresleep(&b->lock); | ||||||
|  |         //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno);
 | ||||||
|         release(&bcache.lock); |         release(&bcache.lock); | ||||||
|         return b; |         return b; | ||||||
|       } |       } | ||||||
|  | @ -80,14 +82,16 @@ bget(uint dev, uint blockno) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // Not cached; recycle some non-busy and clean buffer.
 |   // Not cached; recycle some non-locked and clean buffer.
 | ||||||
|   // "clean" because B_DIRTY and !B_BUSY means log.c
 |   // "clean" because B_DIRTY and not locked means log.c
 | ||||||
|   // hasn't yet committed the changes to the buffer.
 |   // hasn't yet committed the changes to the buffer.
 | ||||||
|   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ |   for(b = bcache.head.prev; b != &bcache.head; b = b->prev){ | ||||||
|     if((b->flags & B_BUSY) == 0 && (b->flags & B_DIRTY) == 0){ |     if(!holdingsleep(&b->lock) && (b->flags & B_DIRTY) == 0){ | ||||||
|       b->dev = dev; |       b->dev = dev; | ||||||
|       b->blockno = blockno; |       b->blockno = blockno; | ||||||
|       b->flags = B_BUSY; |       b->flags = 0;  // XXX
 | ||||||
|  |       acquiresleep(&b->lock); | ||||||
|  |       //cprintf("return buffer %p for blk %d\n", b - bcache.buf, blockno);
 | ||||||
|       release(&bcache.lock); |       release(&bcache.lock); | ||||||
|       return b; |       return b; | ||||||
|     } |     } | ||||||
|  | @ -95,7 +99,7 @@ bget(uint dev, uint blockno) | ||||||
|   panic("bget: no buffers"); |   panic("bget: no buffers"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Return a B_BUSY buf with the contents of the indicated block.
 | // Return a locked buf with the contents of the indicated block.
 | ||||||
| struct buf* | struct buf* | ||||||
| bread(uint dev, uint blockno) | bread(uint dev, uint blockno) | ||||||
| { | { | ||||||
|  | @ -108,22 +112,22 @@ bread(uint dev, uint blockno) | ||||||
|   return b; |   return b; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Write b's contents to disk.  Must be B_BUSY.
 | // Write b's contents to disk.  Must be locked.
 | ||||||
| void | void | ||||||
| bwrite(struct buf *b) | bwrite(struct buf *b) | ||||||
| { | { | ||||||
|   if((b->flags & B_BUSY) == 0) |   if(b->lock.locked == 0) | ||||||
|     panic("bwrite"); |     panic("bwrite"); | ||||||
|   b->flags |= B_DIRTY; |   b->flags |= B_DIRTY; | ||||||
|   iderw(b); |   iderw(b); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Release a B_BUSY buffer.
 | // Release a locked buffer.
 | ||||||
| // Move to the head of the MRU list.
 | // Move to the head of the MRU list.
 | ||||||
| void | void | ||||||
| brelse(struct buf *b) | brelse(struct buf *b) | ||||||
| { | { | ||||||
|   if((b->flags & B_BUSY) == 0) |   if(b->lock.locked == 0) | ||||||
|     panic("brelse"); |     panic("brelse"); | ||||||
| 
 | 
 | ||||||
|   acquire(&bcache.lock); |   acquire(&bcache.lock); | ||||||
|  | @ -134,8 +138,7 @@ brelse(struct buf *b) | ||||||
|   b->prev = &bcache.head; |   b->prev = &bcache.head; | ||||||
|   bcache.head.next->prev = b; |   bcache.head.next->prev = b; | ||||||
|   bcache.head.next = b; |   bcache.head.next = b; | ||||||
| 
 |   releasesleep(&b->lock); | ||||||
|   b->flags &= ~B_BUSY; |  | ||||||
|   wakeup(b); |   wakeup(b); | ||||||
| 
 | 
 | ||||||
|   release(&bcache.lock); |   release(&bcache.lock); | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								buf.h
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								buf.h
									
										
									
									
									
								
							|  | @ -2,12 +2,12 @@ struct buf { | ||||||
|   int flags; |   int flags; | ||||||
|   uint dev; |   uint dev; | ||||||
|   uint blockno; |   uint blockno; | ||||||
|  |   struct sleeplock lock; | ||||||
|   struct buf *prev; // LRU cache list
 |   struct buf *prev; // LRU cache list
 | ||||||
|   struct buf *next; |   struct buf *next; | ||||||
|   struct buf *qnext; // disk queue
 |   struct buf *qnext; // disk queue
 | ||||||
|   uchar data[BSIZE]; |   uchar data[BSIZE]; | ||||||
| }; | }; | ||||||
| #define B_BUSY  0x1  // buffer is locked by some process
 |  | ||||||
| #define B_VALID 0x2  // buffer has been read from disk
 | #define B_VALID 0x2  // buffer has been read from disk
 | ||||||
| #define B_DIRTY 0x4  // buffer needs to be written to disk
 | #define B_DIRTY 0x4  // buffer needs to be written to disk
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								defs.h
									
										
									
									
									
								
							
							
						
						
									
										7
									
								
								defs.h
									
										
									
									
									
								
							|  | @ -6,6 +6,7 @@ struct pipe; | ||||||
| struct proc; | struct proc; | ||||||
| struct rtcdate; | struct rtcdate; | ||||||
| struct spinlock; | struct spinlock; | ||||||
|  | struct sleeplock; | ||||||
| struct stat; | struct stat; | ||||||
| struct superblock; | struct superblock; | ||||||
| 
 | 
 | ||||||
|  | @ -128,6 +129,12 @@ void            release(struct spinlock*); | ||||||
| void            pushcli(void); | void            pushcli(void); | ||||||
| void            popcli(void); | void            popcli(void); | ||||||
| 
 | 
 | ||||||
|  | // sleeplock.c
 | ||||||
|  | void            acquiresleep(struct sleeplock*); | ||||||
|  | void            releasesleep(struct sleeplock*); | ||||||
|  | int             holdingsleep(struct sleeplock*); | ||||||
|  | void            initsleeplock(struct sleeplock*, char*); | ||||||
|  | 
 | ||||||
| // string.c
 | // string.c
 | ||||||
| int             memcmp(const void*, const void*, uint); | int             memcmp(const void*, const void*, uint); | ||||||
| void*           memmove(void*, const void*, uint); | void*           memmove(void*, const void*, uint); | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								exec.c
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								exec.c
									
										
									
									
									
								
							|  | @ -19,6 +19,8 @@ exec(char *path, char **argv) | ||||||
|   pde_t *pgdir, *oldpgdir; |   pde_t *pgdir, *oldpgdir; | ||||||
| 
 | 
 | ||||||
|   begin_op(); |   begin_op(); | ||||||
|  | 
 | ||||||
|  |   cprintf("exec %s\n", path); | ||||||
|   if((ip = namei(path)) == 0){ |   if((ip = namei(path)) == 0){ | ||||||
|     end_op(); |     end_op(); | ||||||
|     return -1; |     return -1; | ||||||
|  | @ -98,6 +100,7 @@ exec(char *path, char **argv) | ||||||
|   proc->tf->esp = sp; |   proc->tf->esp = sp; | ||||||
|   switchuvm(proc); |   switchuvm(proc); | ||||||
|   freevm(oldpgdir); |   freevm(oldpgdir); | ||||||
|  |   cprintf("exec succeeded\n"); | ||||||
|   return 0; |   return 0; | ||||||
| 
 | 
 | ||||||
|  bad: |  bad: | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								fs.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								fs.c
									
										
									
									
									
								
							|  | @ -16,6 +16,7 @@ | ||||||
| #include "mmu.h" | #include "mmu.h" | ||||||
| #include "proc.h" | #include "proc.h" | ||||||
| #include "spinlock.h" | #include "spinlock.h" | ||||||
|  | #include "sleeplock.h" | ||||||
| #include "fs.h" | #include "fs.h" | ||||||
| #include "buf.h" | #include "buf.h" | ||||||
| #include "file.h" | #include "file.h" | ||||||
|  | @ -167,7 +168,7 @@ iinit(int dev) | ||||||
|   initlock(&icache.lock, "icache"); |   initlock(&icache.lock, "icache"); | ||||||
|   readsb(dev, &sb); |   readsb(dev, &sb); | ||||||
|   cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
 |   cprintf("sb: size %d nblocks %d ninodes %d nlog %d logstart %d\
 | ||||||
|           inodestart %d bmap start %d\n", sb.size, sb.nblocks, |  inodestart %d bmap start %d\n", sb.size, sb.nblocks, | ||||||
|           sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, |           sb.ninodes, sb.nlog, sb.logstart, sb.inodestart, | ||||||
|           sb.bmapstart); |           sb.bmapstart); | ||||||
| } | } | ||||||
|  | @ -455,6 +456,13 @@ readi(struct inode *ip, char *dst, uint off, uint n) | ||||||
|   for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ |   for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ | ||||||
|     bp = bread(ip->dev, bmap(ip, off/BSIZE)); |     bp = bread(ip->dev, bmap(ip, off/BSIZE)); | ||||||
|     m = min(n - tot, BSIZE - off%BSIZE); |     m = min(n - tot, BSIZE - off%BSIZE); | ||||||
|  |     /*
 | ||||||
|  |     cprintf("data off %d:\n", off); | ||||||
|  |     for (int j = 0; j < min(m, 10); j++) { | ||||||
|  |       cprintf("%x ", bp->data[off%BSIZE+j]); | ||||||
|  |     } | ||||||
|  |     cprintf("\n"); | ||||||
|  |     */ | ||||||
|     memmove(dst, bp->data + off%BSIZE, m); |     memmove(dst, bp->data + off%BSIZE, m); | ||||||
|     brelse(bp); |     brelse(bp); | ||||||
|   } |   } | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								ide.c
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								ide.c
									
										
									
									
									
								
							|  | @ -9,6 +9,7 @@ | ||||||
| #include "x86.h" | #include "x86.h" | ||||||
| #include "traps.h" | #include "traps.h" | ||||||
| #include "spinlock.h" | #include "spinlock.h" | ||||||
|  | #include "sleeplock.h" | ||||||
| #include "fs.h" | #include "fs.h" | ||||||
| #include "buf.h" | #include "buf.h" | ||||||
| 
 | 
 | ||||||
|  | @ -139,8 +140,8 @@ iderw(struct buf *b) | ||||||
| { | { | ||||||
|   struct buf **pp; |   struct buf **pp; | ||||||
| 
 | 
 | ||||||
|   if(!(b->flags & B_BUSY)) |   if(!holdingsleep(&b->lock)) | ||||||
|     panic("iderw: buf not busy"); |     panic("iderw: buf not locked"); | ||||||
|   if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) |   if((b->flags & (B_VALID|B_DIRTY)) == B_VALID) | ||||||
|     panic("iderw: nothing to do"); |     panic("iderw: nothing to do"); | ||||||
|   if(b->dev != 0 && !havedisk1) |   if(b->dev != 0 && !havedisk1) | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								log.c
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								log.c
									
										
									
									
									
								
							|  | @ -2,6 +2,7 @@ | ||||||
| #include "defs.h" | #include "defs.h" | ||||||
| #include "param.h" | #include "param.h" | ||||||
| #include "spinlock.h" | #include "spinlock.h" | ||||||
|  | #include "sleeplock.h" | ||||||
| #include "fs.h" | #include "fs.h" | ||||||
| #include "buf.h" | #include "buf.h" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Frans Kaashoek
						Frans Kaashoek