代码:https://github.com/RedemptionC/xv6-riscv-6s081/tree/lock

本实验主要是重新设计锁,增加并行性

分别是为kmem和bcache设计

memory allocator

https://blog.csdn.net/RedemptionC/article/details/108127655 这里对kalloc做了一点基本的分析

他的设计是所有的cpu(NCPU为8,但是实际是3个)都使用一个freelist,这样lock contention就很高

要做的改进是为每一个cpu设置一个free list,每个freelist一个锁,这样不同的cpu就能独立的进行分配

首先修改结构体的定义,改为定义一个结构体数组:

struct kmem{struct spinlock lock;struct run *freelist;
};struct kmem kmems[3];

然后在kinit中初始化三个锁,仍然用freerange将全部内存分配给调用它的cpu

void
kinit()
{printf("[kinit] cpu id %d\n",getcpu());for(int i=0;i<3;i++)initlock(&kmems[i].lock, "kmem");freerange(end, (void*)PHYSTOP);
}

其实这里如果将全部的内存均匀的分给每个cpu的freelist,会更好,但是不管怎样,都会面临这样一个问题:当前cpu的freelist为空,但是其他cpu的freelist不为空,此时就需要向其他cpu借内存

修改kalloc

void *
kalloc(void)
{// printf("[kalloc] cpu id %d\n",getcpu());// printkmem();struct run *r;int hart=getcpu();acquire(&kmems[hart].lock);r = kmems[hart].freelist;if(r)kmems[hart].freelist = r->next;release(&kmems[hart].lock);if(!r){// 当前cpu对应的freelist为空 需要从其他cpu对应的freelist借r=steal(hart);}if(r)memset((char*)r, 5, PGSIZE); // fill with junkreturn (void*)r;
}
void *
steal(int skip){// printf("cpu id %d\n",getcpu());struct run * rs=0;for(int i=0;i<3;i++){// 当前cpu的锁已经在外面获取了,这里为了避免死锁,需要跳过if(holding(&kmems[i].lock)){continue;}acquire(&kmems[i].lock);if(kmems[i].freelist!=0){rs=kmems[i].freelist;kmems[i].freelist=rs->next;release(&kmems[i].lock);return (void *)rs;}release(&kmems[i].lock);}// 不管还有没有,都直接返回,不用panicreturn (void *)rs;
}

执行kfree的时候,只要将内存回收到当前cpu的freelist即可

这样,即可通过kalloctest:

Buffer cache

在bio.c中,可以看到,所有的buffer都被组织到了一条链表中,因此如果有多个进程要使用buffer,他们并发的请求只能被顺序的处理

指导书给出了一种优化的办法:使用哈希表,separate chaining的方式来组织buffer,使用blockno作为key

具体我在代码注释里写的很清楚了:

// Buffer cache.
//
// The buffer cache is a linked list of buf structures holding
// cached copies of disk block contents.  Caching disk blocks
// in memory reduces the number of disk reads and also provides
// a synchronization point for disk blocks used by multiple processes.
//
// Interface:
// * To get a buffer for a particular disk block, call bread.
// * After changing buffer data, call bwrite to write it to disk.
// * When done with the buffer, call brelse.
// * Do not use the buffer after calling brelse.
// * Only one process at a time can use a buffer,
//     so do not keep them longer than necessary.#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "riscv.h"
#include "defs.h"
#include "fs.h"
#include "buf.h"#define NBUCKETS 13struct {// 每个bucket一个lock// hashbucket.next是当前bucket的MRUstruct spinlock lock[NBUCKETS];struct buf buf[NBUF];struct buf hashbucket[NBUCKETS];
} bcache;int bhash(int blockno){return blockno%NBUCKETS;
}void
binit(void)
{struct buf *b;for(int i=0;i<NBUCKETS;i++){initlock(&bcache.lock[i], "bcache.bucket");// 仍然将每个bucket的头节点都指向自己b=&bcache.hashbucket[i];b->prev = b;b->next = b;}// 此时因为buffer没有和磁盘块对应起来,所以blockno全部为初始值0,将其全部放在第一个bucket中// 至于其他bucket缺少buffer该怎么解决,在bget里阐述for(b = bcache.buf; b < bcache.buf+NBUF; b++){// 虽然看起来复杂了点,但仍然是插在表头b->next = bcache.hashbucket[0].next;b->prev = &bcache.hashbucket[0];initsleeplock(&b->lock, "buffer");bcache.hashbucket[0].next->prev = b;bcache.hashbucket[0].next = b;}
}// 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;int h=bhash(blockno);acquire(&bcache.lock[h]);// 首先在blockno对应的bucket中找,refcnt可能为0,也可能不为0for(b = bcache.hashbucket[h].next; b != &bcache.hashbucket[h]; b = b->next){if(b->dev == dev && b->blockno == blockno){b->refcnt++;release(&bcache.lock[h]);acquiresleep(&b->lock);return b;}}// 如果在h对应的bucket中没有找到,那么需要到其他bucket中找,这种情况不会少见,因为// binit中,我们就把所有的buffer都插入到了第一个bucket中(当时blockno都是0// 此时原来bucket的锁还没有释放,因为我们在其他bucket中找到buffer后,还要将其插入到原bucket中int nh=(h+1)%NBUCKETS; // nh表示下一个要探索的bucket,当它重新变成h,说明所有的buffer都bussy(refcnt不为0),此时// 如之前设计的,panicwhile(nh!=h){acquire(&bcache.lock[nh]);// 获取当前bocket的锁for(b = bcache.hashbucket[nh].prev; b != &bcache.hashbucket[nh]; b = b->prev){if(b->refcnt == 0) {b->dev = dev;b->blockno = blockno;b->valid = 0;b->refcnt = 1;// 从原来bucket的链表中断开b->next->prev=b->prev;b->prev->next=b->next;release(&bcache.lock[nh]);// 插入到blockno对应的bucket中去// 												

MIT-6.s081-OS Lab: locks相关推荐

  1. 2020 MIT6.s081 os Lab: page tables

    文章目录 实验链接 Print a page table A kernel page table per process Simplify 实验结果 提交实验 查看结果 参考链接 github地址 友 ...

  2. MIT 6.s081学习笔记

    MIT 6.s081学习笔记 introduction 计算机组织结构: 最底部是一些硬件资源,包括了CPU,内存,磁盘,网卡 最上层会运行各种应用程序,比如vim,shell等,这些就是正在运行的所 ...

  3. 「实验记录」MIT 6.S081 Lab7 multithreading

    #Lab7: multithreading I. Source II. My Code III. Motivation IV. Uthread: switching between threads ( ...

  4. MIT 6.S081 Lab4 traps

    #Lab4: traps #Source #My Code #Motivation #Backtrace (moderate) #Motivation #Solution #S0 - RISC-V 栈 ...

  5. MIT 6.S081 lab 11:Networking

    ​ 背景 在你开始写代码前,你可能会发现xv6 book中的第五章:中断和设备驱动是很有帮助的. 你将使用一个叫做E1000的网络设备来处理网络通信.对于xv6(以及你写的驱动),E1000看起来像一 ...

  6. 操作系统实验Lab 1:Xv6 and Unix utilities(MIT 6.S081 FALL 2020)

    Lab 1 Xv6 and Unix utilities 实验要求链接 Boot xv6 (easy) 实验目的 切换到 xv6-labs-2020 代码的 util 分支,并利用 QEMU 模拟器启 ...

  7. MIT 6.S081 lab 5:lazy page allocation

    1 Lab lab 5就是去实现xv6 book 4.6中写的 Lazy page allocation 有个问题:page fault的trap是如何出现的? 1.1 Eliminate alloc ...

  8. OS Lab 【Traps】

    一.实验内容: Part A RISC-V assembly 见问题回答 Part B Backtrace Add the prototype for your backtrace() to kern ...

  9. 6.S081 Xv6 Lab 5: lazy page allocation

    Lab: xv6 lazy page allocation https://pdos.csail.mit.edu/6.S081/2020/labs/lazy.html 新的 2020 版哦. $ gi ...

  10. MIT 6.S081 实验5 笔记与心得

    Lab 5:Lazy 文章目录 Lab 5:Lazy 前期准备 Eliminate allocation from sbrk() ([easy](https://pdos.csail.mit.edu/ ...

最新文章

  1. linux shell 创建序列数组(list,array)方法
  2. win7(旗舰版)下,OleLoadPicture 加载内存中的图片(MagickGetImageBlob),返回值 0
  3. Framebuffer的配置及应用——先转载留着,以后一定要弄懂
  4. Spring运行期间配置文件解析返回
  5. 7个你可能不认识的CSS单位
  6. mysql id 字段类型转换_mysql 数据类型转换
  7. [傅里叶变换及其应用学习笔记] 二十四. 级联,脉冲响应
  8. Java树形转扁平_js把树形数据转成扁平数据
  9. 苦思冥想时,吃什么,尝一口,酥脆掉渣,鲜掉眉毛!
  10. linux如何卸载光驱显示busy,关于linux卸载设备时的busy问题处理
  11. python 函数重载_python中有函数重载吗
  12. autotools 学习
  13. 个人对回调函数的理解(personal understanding of callback function)
  14. 消灭WinRAR广告
  15. “交通·未来”第22期:城市轨道交通管理与控制优化:相关问题及方法
  16. Win7系统怎么强制格式化U盘
  17. 用Python自制一个百度一下,这操作可还行
  18. 100+篇论文合集:GNN在NLP中的应用
  19. 【技术贴】自己制作支持QQ空间背景音乐的链接教程||QQ免费空间音乐外链自己上传制作教程...
  20. 人力资源管理理论与实务第三章

热门文章

  1. 美女画廊(点击上面的图片下面进行显示)
  2. 苹果的破局几招:修漏洞、降价、官方认证翻新机……
  3. 编译器整数除法的优化
  4. java fuoco车架_为速度而生 JAVA Fuoco铝合金气动公路
  5. 二本电气工程应届生收割5个offer,转型大数据真的与专业无关
  6. 游戏服务器开发环境搭建
  7. 在asp中实现由动态网页转变为静态网页
  8. 中国剩余定理(c语言)
  9. Linux xorg 调整分辨率,编写xorg.conf解决Ubuntu分辨率不可调的问题
  10. 微服务项目:尚融宝(40)(核心业务流程:申请借款额度(3))