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..52711bad 100644 --- a/kernel/bio.c +++ b/kernel/bio.c @@ -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"); } @@ -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]); } 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..c9caca6d 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -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, @@ -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) @@ -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. @@ -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;inext; + 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..ec5f17d9 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 13 #define FSSIZE 2000 // size of file system in blocks #define MAXPATH 128 // maximum file path name #define NDISK 2