国庆没啥事干,现在还剩3个半lab,快要做完啦,希望能有始有终,人活着真难,太难了。。。
Memmory其实就是用freelist实现的,而缓冲区Cache其实也是用freelist实现的,不过缓冲在disk的上一层,因为disk读取很慢,缓冲的定义在buf.h
struct buf {
int valid; // has data been read from disk? 缓存是否有数据可读,新分配的缓存,valid为0,
int disk; // does disk "own" buf?
uint dev;
uint blockno; //缓冲对应的磁盘块号
struct sleeplock lock;
uint refcnt; //有多少线程引用了这个缓冲,我猜的
struct buf *prev; // LRU cache list
struct buf *next;
uchar data[BSIZE];
};
Memmory Allocator
1.修改kalloc.c
struct {
struct spinlock lock;
struct run *freelist;
} kmem[NCPU];
2. 修改kinit
void
kinit()
{
push_off();
int id = cpuid();
initlock(&kmem[id].lock, "kmem");
pop_off();
freerange(end, (void*)PHYSTOP);
}
3. 修改kfree
void
kfree(void *pa)
{
struct run *r;
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
push_off();
int id = cpuid();
pop_off();
acquire(&kmem[id].lock);
r->next = kmem[id].freelist;
kmem[id].freelist = r;
release(&kmem[id].lock);
}
4. 修改kalloc
void *
kalloc(void)
{
struct run *r;
push_off();
int id = cpuid();
pop_off();
acquire(&kmem[id].lock);
r = kmem[id].freelist;
if(r)
kmem[id].freelist = r->next;
release(&kmem[id].lock);
if(!r)
{
for(int i = 0; i < NCPU; i++)
{
acquire(&kmem[i].lock);
if(kmem[i].freelist) {
r = kmem[i].freelist;
kmem[i].freelist = r->next;
}
release(&kmem[i].lock);
if(r) break;
}
}
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
Buffer Cache
1. 修改bcache结构体
#define NBUCKETS 13
struct {
struct spinlock lock[NBUCKETS];
struct buf buf[NBUF];
// Linked list of all buffers, through prev/next.
// Sorted by how recently the buffer was used.
// head.next is most recent, head.prev is least.
struct buf head[NBUCKETS];
} bcache;
2. 修改 bget
static struct buf*
bget(uint dev, uint blockno)
{
struct buf *b;
int i = hash(blockno);
acquire(&bcache.lock[i]);
// Is the block already cached?
for(b = bcache.head[i].next; b != &bcache.head[i]; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
release(&bcache.lock[i]);
acquiresleep(&b->lock);
return b;
}
}
// Not cached.
// Recycle the least recently used (LRU) unused buffer.
for(b = bcache.head[i].prev; b != &bcache.head[i]; b = b->prev){
if(b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
release(&bcache.lock[i]);
acquiresleep(&b->lock);
return b;
}
}
for(int j = (i+1) % NBUCKETS; j != i; j = (j+1) %NBUCKETS) {
acquire(&bcache.lock[j]);
for(b = bcache.head[j].prev; b != &bcache.head[j]; b = b->prev){
if(b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
b->next->prev = b->prev;
b->prev->next = b->next;
release(&bcache.lock[j]);
b->next = bcache.head[i].next;
b->prev = &bcache.head[i];
bcache.head[i].next->prev = b;
bcache.head[i].next = b;
release(&bcache.lock[i]);
acquiresleep(&b->lock);
return b;
}
}
release(&bcache.lock[j]); //记得释放锁,因为有可能走不进 cnt == 0 的if语句
}
panic("bget: no buffers");
}
3. 修改brels
void
brelse(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("brelse");
releasesleep(&b->lock);
int i = hash(b->blockno);
acquire(&bcache.lock[i]);
b->refcnt--;
if (b->refcnt == 0) {
// no one is waiting for it.
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head[i].next;
b->prev = &bcache.head[i];
bcache.head[i].next->prev = b;
bcache.head[i].next = b;
}
release(&bcache.lock[i]);
}
4. 修改bpin和bunpin
void
bpin(struct buf *b) {
int i = hash(b->blockno);
acquire(&bcache.lock[i]);
b->refcnt++;
release(&bcache.lock[i]);
}
void
bunpin(struct buf *b) {
int i = hash(b->blockno);
acquire(&bcache.lock[i]);
b->refcnt--;
release(&bcache.lock[i]);
}
5. 修改binit
void
binit(void)
{
struct buf *b;
initlock(&bcache.lock, "bcache");
// Create linked list of buffers
for(int i = 0; i < NBUCKETS; i++) {
bcache.head[i].prev = &bcache.head[i];
bcache.head[i].next = &bcache.head[i];
}
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
b->next = bcache.head[0].next;
b->prev = &bcache.head[0];
initsleeplock(&b->lock, "buffer");
bcache.head[0].next->prev = b;
bcache.head[0].next = b;
}
}
7. 添加hash
int hash(int blockno) {
return blockno % NBUCKETS;
}
8. 运行结果