From 0456af4fe35230ba47598d3b92fca8b7b65dac84 Mon Sep 17 00:00:00 2001 From: RustLee <13689524996@163.com> Date: Tue, 24 Nov 2020 21:47:43 +0800 Subject: [PATCH 1/4] Ex3 code finish --- .vscode/settings.json | 6 +++ kernel/bio.c | 120 ++++++++++++++++++++++++++++++------------ kernel/buf.h | 1 + kernel/kalloc.c | 44 ++++++++++++---- kernel/param.h | 1 + 5 files changed, 126 insertions(+), 46 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..03dc6f00 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "sleeplock.h": "c", + "spinlock.h": "c" + } +} \ No newline at end of file diff --git a/kernel/bio.c b/kernel/bio.c index 9ce1c50d..e5a514eb 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -24,12 +24,13 @@ #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 @@ -37,18 +38,32 @@ binit(void) { struct buf *b; - initlock(&bcache.lock, "bcache"); - + for (int i = 0; i < NBUCKET; 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; - initsleeplock(&b->lock, "buffer"); - bcache.head.next->prev = b; - bcache.head.next = b; + for (b = bcache.buf; b < bcache.buf+NBUF; b++) + { + initsleeplock(&b->lock,"buffer"); + b->used = 0; + } + + // bcache.head.prev = &bcache.head; + // bcache.head.next = &bcache.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]; } + + // for(b = bcache.buf; b < bcache.buf+NBUF; b++){ + // b->next = bcache.head.next; + // b->prev = &bcache.head; + // initsleeplock(&b->lock, "buffer"); + // bcache.head.next->prev = b; + // bcache.head.next = b; + // } } // Look through buffer cache for block on device dev. @@ -59,30 +74,54 @@ bget(uint dev, uint blockno) { struct buf *b; - acquire(&bcache.lock); + uint id = ((((uint64)dev) << 32) | blockno) % NBUCKET; + + 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(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 < NBUF; i++) + { + if (!bcache.buf[i].used && __sync_bool_compare_and_swap(&bcache.buf[i].used, 0, 1)) { + b = &bcache.buf[i]; + if (b->refcnt == 0) + { + b->dev = dev; + b->blockno = blockno; + b->valid = 0; + b->refcnt = 1; + 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[id]); + acquiresleep(&b->lock); + return b; + } + } } + + panic("bget: no buffers"); } @@ -119,33 +158,44 @@ brelse(struct buf *b) 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->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->next = bcache.head.next; + // b->prev = &bcache.head; + // bcache.head.next->prev = b; + // bcache.head.next = b; + if (!__sync_bool_compare_and_swap(&b->used, 0, 1)) + { + panic("brelse_cas"); + } + } - 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]); } diff --git a/kernel/buf.h b/kernel/buf.h index 4616e9ec..513191e6 100644 --- a/kernel/buf.h +++ b/kernel/buf.h @@ -7,6 +7,7 @@ struct buf { uint refcnt; struct buf *prev; // LRU cache list struct buf *next; + uint used; uchar data[BSIZE]; }; diff --git a/kernel/kalloc.c b/kernel/kalloc.c index fa6a0aca..62d8c493 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -19,24 +19,27 @@ struct run { }; 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, @@ -46,6 +49,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) @@ -56,10 +61,12 @@ kfree(void *pa) r = (struct run*)pa; - acquire(&kmem.lock); - r->next = kmem.freelist; - kmem.freelist = r; - release(&kmem.lock); + 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. @@ -68,15 +75,30 @@ 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]; if(r) - kmem.freelist = r->next; - release(&kmem.lock); + kmem.freelist[id] = r->next; + release(&kmem.lock[id]); + if (!r) { + for (int i = 0; i < NCPU; i++) { + acquire(&kmem.lock[i]); + r = kmem.freelist[id]; + 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; } diff --git a/kernel/param.h b/kernel/param.h index 8e4ca984..73f430ea 100644 --- a/kernel/param.h +++ b/kernel/param.h @@ -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 97 #define FSSIZE 2000 // size of file system in blocks #define MAXPATH 128 // maximum file path name #define NDISK 2 From d11b5527f1b5c36a96b183de398e3579de6d8359 Mon Sep 17 00:00:00 2001 From: RustLee <13689524996@163.com> Date: Fri, 27 Nov 2020 09:41:06 +0800 Subject: [PATCH 2/4] Ex3 finished --- kernel/bio.c | 72 +++++++++++++++++++++---------------------------- kernel/kalloc.c | 16 +++++++---- kernel/param.h | 2 +- 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/kernel/bio.c b/kernel/bio.c index e5a514eb..dfc2f88e 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -40,30 +40,23 @@ binit(void) 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 for (b = bcache.buf; b < bcache.buf+NBUF; b++) { - initsleeplock(&b->lock,"buffer"); + //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.bucket_head[id].next->prev = b; + bcache.bucket_head[id].next = b; b->used = 0; } - // bcache.head.prev = &bcache.head; - // bcache.head.next = &bcache.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]; - } - - // for(b = bcache.buf; b < bcache.buf+NBUF; b++){ - // b->next = bcache.head.next; - // b->prev = &bcache.head; - // initsleeplock(&b->lock, "buffer"); - // bcache.head.next->prev = b; - // bcache.head.next = b; - // } } // Look through buffer cache for block on device dev. @@ -73,8 +66,8 @@ static struct buf* bget(uint dev, uint blockno) { struct buf *b; - - uint id = ((((uint64)dev) << 32) | blockno) % NBUCKET; + //printf("get\n" ); + uint id = (/*(((uint64)dev) << 32) |*/ blockno) % NBUCKET; acquire(&bcache.bucket_lock[id]); @@ -89,36 +82,36 @@ bget(uint dev, uint blockno) } // 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 < NBUF; i++) + + for (int i = 0; i < NBUCKET; i++) { - if (!bcache.buf[i].used && __sync_bool_compare_and_swap(&bcache.buf[i].used, 0, 1)) { - b = &bcache.buf[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; } } + } + } @@ -155,7 +148,7 @@ brelse(struct buf *b) { if(!holdingsleep(&b->lock)) panic("brelse"); - + //printf("brekkes\n" ); releasesleep(&b->lock); uint id = ((((uint64)b->dev) << 32) | b->blockno) % NBUCKET; @@ -166,15 +159,10 @@ brelse(struct buf *b) // no one is waiting for it. 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; - if (!__sync_bool_compare_and_swap(&b->used, 0, 1)) - { - panic("brelse_cas"); - } - + 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[id]); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 62d8c493..df4a3ba5 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -35,10 +35,12 @@ 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(); } @@ -77,6 +79,7 @@ kalloc(void) { push_off(); int id = cpuid(); + struct run *r; acquire(&kmem.lock[id]); @@ -84,21 +87,24 @@ kalloc(void) if(r) kmem.freelist[id] = r->next; release(&kmem.lock[id]); - if (!r) { - for (int i = 0; i < NCPU; i++) { + + if(!r) { + for(int i=0;inext; release(&kmem.lock[i]); - if (r) + if(r) break; } } + if(r) memset((char*)r, 5, PGSIZE); // fill with junk pop_off(); + return (void*)r; } diff --git a/kernel/param.h b/kernel/param.h index 73f430ea..ec5f17d9 100644 --- a/kernel/param.h +++ b/kernel/param.h @@ -9,7 +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 97 +#define NBUCKET 13 #define FSSIZE 2000 // size of file system in blocks #define MAXPATH 128 // maximum file path name #define NDISK 2 From 261084ecb58f8341f366a91643e993cc6fe58c05 Mon Sep 17 00:00:00 2001 From: RustLee <48178505+RustLee@users.noreply.github.com> Date: Fri, 27 Nov 2020 17:03:44 +0800 Subject: [PATCH 3/4] Update kalloc.c --- kernel/kalloc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/kalloc.c b/kernel/kalloc.c index df4a3ba5..18c9ae06 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -12,7 +12,6 @@ void freerange(void *pa_start, void *pa_end); extern char end[]; // first address after kernel. - // defined by kernel.ld. struct run { struct run *next; From 937771c9e9e1f994d3cea422579f97c4c69c86b7 Mon Sep 17 00:00:00 2001 From: RustLee <48178505+RustLee@users.noreply.github.com> Date: Thu, 24 Dec 2020 13:41:02 +0800 Subject: [PATCH 4/4] =?UTF-8?q?lock=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/bio.c | 6 +++++- kernel/kalloc.c | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/kernel/bio.c b/kernel/bio.c index dfc2f88e..52711bad 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -23,6 +23,7 @@ #include "fs.h" #include "buf.h" +//本质是一个双向循环链表 struct { uint unused[NBUF]; struct buf buf[NBUF]; @@ -37,7 +38,7 @@ void binit(void) { struct buf *b; - + //将b插入在head的头部 for (int i = 0; i < NBUCKET; i++) { bcache.bucket_head[i].prev = &bcache.bucket_head[i]; @@ -62,6 +63,7 @@ binit(void) // 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) { @@ -157,8 +159,10 @@ brelse(struct buf *b) b->refcnt--; if (b->refcnt == 0) { // no one is waiting for it. + //将b脱出 b->next->prev = b->prev; b->prev->next = b->next; + //将b接入 b->next = bcache.bucket_head[id].next; b->prev = &bcache.bucket_head[id]; bcache.bucket_head[id].next->prev = b; diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 18c9ae06..c9caca6d 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -16,7 +16,7 @@ extern char end[]; // first address after kernel. struct run { struct run *next; }; - +//将kalloc的共享freelist改为每个CPU独立的freelist struct { struct spinlock lock[NCPU]; struct run *freelist[NCPU]; @@ -62,6 +62,7 @@ kfree(void *pa) r = (struct run*)pa; + //调用cpuid()获取相应的id,然后将被释放的块插入相应的free list acquire(&kmem.lock[id]); r->next = kmem.freelist[id]; kmem.freelist[id] = r; @@ -83,10 +84,11 @@ kalloc(void) acquire(&kmem.lock[id]); r = kmem.freelist[id]; + //如果当前CPU的free list不为空,pop一个run出来,初始化后返回给调用者 if(r) kmem.freelist[id] = r->next; release(&kmem.lock[id]); - + //如果当前CPU对应的free list为空,则查询其它CPU对应的free list if(!r) { for(int i=0;i