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…
Reference in a new issue