Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ex3 code finish #4

Open
wants to merge 4 commits into
base: lock
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"files.associations": {
"sleeplock.h": "c",
"spinlock.h": "c"
}
}
112 changes: 77 additions & 35 deletions kernel/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,66 +23,100 @@
#include "fs.h"
#include "buf.h"

//本质是一个双向循环链表
struct {
struct spinlock lock;
uint unused[NBUF];
struct buf buf[NBUF];

// Linked list of all buffers, through prev/next.
// head.next is most recently used.
struct buf head;
struct buf bucket_head[NBUCKET];
struct spinlock bucket_lock[NBUCKET];
} bcache;

void
binit(void)
{
struct buf *b;

initlock(&bcache.lock, "bcache");

//将b插入在head的头部
for (int i = 0; i < NBUCKET; i++)
{
bcache.bucket_head[i].prev = &bcache.bucket_head[i];
bcache.bucket_head[i].next = &bcache.bucket_head[i];
initlock(&bcache.bucket_lock[i], "bcache");
}
// Create linked list of buffers
bcache.head.prev = &bcache.head;
bcache.head.next = &bcache.head;
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
b->next = bcache.head.next;
b->prev = &bcache.head;
for (b = bcache.buf; b < bcache.buf+NBUF; b++)
{
//initsleeplock(&b->lock,"buffer");b->next = bcache.head.next;
uint id = ((((uint64)b->dev) << 32) | b->blockno) % NBUCKET;
b->next = bcache.bucket_head[id].next;
b->prev = &bcache.bucket_head[id];
initsleeplock(&b->lock, "buffer");
bcache.head.next->prev = b;
bcache.head.next = b;
bcache.bucket_head[id].next->prev = b;
bcache.bucket_head[id].next = b;
b->used = 0;
}

}

// Look through buffer cache for block on device dev.
// If not found, allocate a buffer.
// In either case, return locked buffer.
//修改源代码以支持哈希桶结构
static struct buf*
bget(uint dev, uint blockno)
{
struct buf *b;
//printf("get\n" );
uint id = (/*(((uint64)dev) << 32) |*/ blockno) % NBUCKET;

acquire(&bcache.lock);
acquire(&bcache.bucket_lock[id]);

// Is the block already cached?
for(b = bcache.head.next; b != &bcache.head; b = b->next){
for(b = bcache.bucket_head[id].next; b != &bcache.bucket_head[id]; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
release(&bcache.lock);
release(&bcache.bucket_lock[id]);
acquiresleep(&b->lock);
return b;
}
}

// Not cached; recycle an unused buffer.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
if(b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
release(&bcache.lock);
acquiresleep(&b->lock);
return b;

for (int i = 0; i < NBUCKET; i++)
{
if(i != id){
for (b = bcache.bucket_head[i].prev; b != &bcache.bucket_head[i]; b = b->prev) {
if (b->refcnt == 0)
{
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
acquire(&bcache.bucket_lock[i]);

b->next->prev = b->prev;
b->prev->next = b->next;

b->next = bcache.bucket_head[id].next;
b->prev = &bcache.bucket_head[id];

bcache.bucket_head[id].next->prev = b;
bcache.bucket_head[id].next = b;

release(&bcache.bucket_lock[i]);
release(&bcache.bucket_lock[id]);
acquiresleep(&b->lock);
return b;
}
}
}

}


panic("bget: no buffers");
}

Expand Down Expand Up @@ -116,36 +150,44 @@ brelse(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("brelse");

//printf("brekkes\n" );
releasesleep(&b->lock);

acquire(&bcache.lock);
uint id = ((((uint64)b->dev) << 32) | b->blockno) % NBUCKET;

acquire(&bcache.bucket_lock[id]);
b->refcnt--;
if (b->refcnt == 0) {
// no one is waiting for it.
//将b脱出
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head.next;
b->prev = &bcache.head;
bcache.head.next->prev = b;
bcache.head.next = b;
//将b接入
b->next = bcache.bucket_head[id].next;
b->prev = &bcache.bucket_head[id];
bcache.bucket_head[id].next->prev = b;
bcache.bucket_head[id].next = b;
}

release(&bcache.lock);
release(&bcache.bucket_lock[id]);
}

void
bpin(struct buf *b) {
acquire(&bcache.lock);
uint id = ((((uint64)b->dev) << 32) | b->blockno) % NBUCKET;

acquire(&bcache.bucket_lock[id]);
b->refcnt++;
release(&bcache.lock);
release(&bcache.bucket_lock[id]);
}

void
bunpin(struct buf *b) {
acquire(&bcache.lock);
uint id = ((((uint64)b->dev) << 32) | b->blockno) % NBUCKET;

acquire(&bcache.bucket_lock[id]);
b->refcnt--;
release(&bcache.lock);
release(&bcache.bucket_lock[id]);
}


1 change: 1 addition & 0 deletions kernel/buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct buf {
uint refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
uint used;
uchar data[BSIZE];
};

55 changes: 42 additions & 13 deletions kernel/kalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,35 @@
void freerange(void *pa_start, void *pa_end);

extern char end[]; // first address after kernel.
// defined by kernel.ld.

struct run {
struct run *next;
};

//将kalloc的共享freelist改为每个CPU独立的freelist
struct {
struct spinlock lock;
struct run *freelist;
struct spinlock lock[NCPU];
struct run *freelist[NCPU];
} kmem;

void
kinit()
{
initlock(&kmem.lock, "kmem");
for (int i = 0; i < NCPU; i++)
initlock(&kmem.lock[i], "kmem");
freerange(end, (void*)PHYSTOP);
}

void
freerange(void *pa_start, void *pa_end)
{
push_off();

char *p;
p = (char*)PGROUNDUP((uint64)pa_start);
for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
kfree(p);

pop_off();
}

// Free the page of physical memory pointed at by v,
Expand All @@ -46,6 +50,8 @@ freerange(void *pa_start, void *pa_end)
void
kfree(void *pa)
{
push_off();
int id = cpuid();
struct run *r;

if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
Expand All @@ -56,10 +62,13 @@ kfree(void *pa)

r = (struct run*)pa;

acquire(&kmem.lock);
r->next = kmem.freelist;
kmem.freelist = r;
release(&kmem.lock);
//调用cpuid()获取相应的id,然后将被释放的块插入相应的free list
acquire(&kmem.lock[id]);
r->next = kmem.freelist[id];
kmem.freelist[id] = r;
release(&kmem.lock[id]);

pop_off();
}

// Allocate one 4096-byte page of physical memory.
Expand All @@ -68,15 +77,35 @@ kfree(void *pa)
void *
kalloc(void)
{
push_off();
int id = cpuid();

struct run *r;

acquire(&kmem.lock);
r = kmem.freelist;
acquire(&kmem.lock[id]);
r = kmem.freelist[id];
//如果当前CPU的free list不为空,pop一个run出来,初始化后返回给调用者
if(r)
kmem.freelist = r->next;
release(&kmem.lock);
kmem.freelist[id] = r->next;
release(&kmem.lock[id]);
//如果当前CPU对应的free list为空,则查询其它CPU对应的free list
if(!r) {
for(int i=0;i<NCPU;i++) {
acquire(&kmem.lock[i]);
r = kmem.freelist[i];
if(r)
kmem.freelist[i] = r->next;
release(&kmem.lock[i]);

if(r)
break;
}
}

if(r)
memset((char*)r, 5, PGSIZE); // fill with junk

pop_off();

return (void*)r;
}
1 change: 1 addition & 0 deletions kernel/param.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define MAXOPBLOCKS 10 // max # of blocks any FS op writes
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define NBUCKET 13
#define FSSIZE 2000 // size of file system in blocks
#define MAXPATH 128 // maximum file path name
#define NDISK 2