当前位置: 首页 > wzjs >正文

企业网站设计的功能企业 网站 设计

企业网站设计的功能,企业 网站 设计,大型电商网站建设,青海和城乡建设厅网站本篇是 MIT6.S081 操作系统课程 Lab6 的实验笔记,目标是完成 fork() 写时复制(Copy-on-Write)的功能,算是上一个懒分配实验的延伸。 未修改的 fork() 会复制父进程所有的内存到子进程,这个过程耗时且浪费内存&#xf…

本篇是 MIT6.S081 操作系统课程 Lab6 的实验笔记,目标是完成 fork() 写时复制(Copy-on-Write)的功能,算是上一个懒分配实验的延伸。

未修改的 fork() 会复制父进程所有的内存到子进程,这个过程耗时且浪费内存,写时复制的核心思想是:

  • fork 阶段,新创建的子进程页表,映射到父进程的物理地址,父子进程页表指向的物理地址是相同的
  • 同时,将共享的物理页面映射成 只读。
  • 只有当父子进程中的某一方尝试修改共享的页面时,触发页面错误,OS 才真正为子进程复制该页面。
  • Lab6 地址:https://pdos.csail.mit.edu/6.828/2020/labs/cow.html
  • 我的实验记录:https://github.com/yibaoshan/xv6-labs-2020/tree/cow

在开始实验之前,你需要:

  1. 观看 Lecture 8 课程录播视频:Interrupts(中断)
    • YouTube 原版:https://www.youtube.com/watch?v=zRnGNndcVEA
    • 哔哩哔哩中译版:https://www.bilibili.com/video/BV19k4y1C7kA?vd_source=6bce9c6d7d453b39efb8a96f5c8ebb7f&p=8
  2. 阅读 《xv6 book》 第五章: 中断和设备驱动
    • 英文原版:https://pdos.csail.mit.edu/6.828/2020/xv6/book-riscv-rev1.pdf
    • 中译版:https://xv6.dgs.zone/tranlate_books/book-riscv-rev1/c5/s0.html

Implement copy-on write(hard)

Your task is to implement copy-on-write fork in the xv6 kernel. You are done if your modified kernel executes both the cowtest and usertests programs successfully.

实现 copy-on-write fork 功能,并通过 cowtest 和 usertests 测试程序。

实验要求不能在上一节懒加载代码的基础上改,请切换到 cow 分支。

实现思路视频中讲得比较清楚:

  1. 延迟复制/释放,把一个物理页的复制(kalloc() then memmove())和释放(kfree())操作,改为记录这个物理页面被多少个进程引用
    • 创建新的物理页,引用数 +1
    • 复制一个物理页面,该物理页的引用数 +1
    • 进程释放一个物理页面,引用计数 -1,只有最后一个进程解除引用时,才可以真正的释放物理内存。
    • 执行写时复制,物理页的引用数也需要 -1
  2. 写时复制,本实验的核心功能,当一个进程尝试向一个共享页写入的时候,执行创建新物理页并复制。
    • 为 PTE 新增标识,用来标记这个物理页是写时复制的共享页面。
    • 触发页面错误,OS 才真正为子进程复制该页面。

1、延迟复制/释放

首先我们需要新增引用记数,用来记录每个物理页面被多少个进程引用,内存的申请释放都在 kalloc.c 文件

...
struct {struct spinlock lock;struct run *freelist;
} kmem;// 物理地址转 index
#define PA2IDX(p) (((uint64)(p)) / PGSIZE)struct {struct spinlock lock; // 保证并发安全int ref_arr[PHYSTOP / PGSIZE]; // 每个物理页面的引用次数
} page_ref; // 模仿 kmem 新建页面引用结构
...

新建 page_ref 结构体,里面有个数组用来存储物理页面的引用次数,还有个 lock 自旋锁,用来保证多 CPU 的并发安全。

void
kinit()
{initlock(&kmem.lock, "kmem");initlock(&page_ref.lock, "pageref"); // 初始化 page_ref.lockfreerange(end, (void*)PHYSTOP);
}

初始化 page_ref.lock

void *
kalloc(void)
{...if(r){memset((char*)r, 5, PGSIZE); // fill with junk// 如果是新分配的有效物理页,引用计数为 1page_ref.ref_arr[PA2IDX(r)] = 1;}return (void*)r;
}

如果是新分配的有效物理页,引用计数需要为 1。

kfree() 释放函数也需要修改,释放一个物理页面,引用计数 -1,只有最后一个进程解除引用,没有进程映射到该物理页了,才真正释放页面

void
kfree(void *pa)
{struct run *r;if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)panic("kfree");acquire(&page_ref.lock);// 只有页面的引用计数为 0,没有进程映射到该物理页了,才真正释放页面if(--page_ref.ref_arr[PA2IDX(pa)] <= 0) {// Fill with junk to catch dangling refs.memset(pa, 1, PGSIZE);r = (struct run*)pa;acquire(&kmem.lock);r->next = kmem.freelist;kmem.freelist = r;release(&kmem.lock);}release(&page_ref.lock);
}

同时,还需要给外部提供增加引用次数和复制物理页的函数


// 如果有必要,克隆一页物理页
void *ktry_pgclone(void *pa) {acquire(&page_ref.lock);// 这个物理页本来就只有一个地方引用,直接返回if(page_ref.ref_arr[PA2IDX(pa)] <= 1) {release(&page_ref.lock);return pa;}// 申请一页物理页uint64 newpa = (uint64)kalloc();if(newpa == 0) {release(&page_ref.lock);return 0;}// 复制老物理页内容到新页memmove((void*)newpa, (void*)pa, PGSIZE);// 老物理页引用减一page_ref.ref_arr[PA2IDX(pa)]--;release(&page_ref.lock);return (void*)newpa;
}// 增加物理页面的引用次数
void kparef_inc(void *pa) {acquire(&page_ref.lock);page_ref.ref_arr[PA2IDX(pa)]++;release(&page_ref.lock);
}

把原先的 vm.c 里面的 copy 工作,改为对这个物理页的引用次数 +1

int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{pte_t *pte;uint64 pa, i;uint flags;
//  char *mem; // 不需要新的内存空间的for(i = 0; i < sz; i += PGSIZE){if((pte = walk(old, i, 0)) == 0)panic("uvmcopy: pte should exist");if((*pte & PTE_V) == 0)panic("uvmcopy: page not present");pa = PTE2PA(*pte);// 如果页面是可写权限,那把它标记为 COW 并移除写权限if (*pte & PTE_W) {*pte = (*pte & ~PTE_W) | PTE_COW;}flags = PTE_FLAGS(*pte);// 这里取消申请内存并复制的操作
//    if((mem = kalloc()) == 0)
//      goto err;
//    memmove(mem, (char*)pa, PGSIZE);// 将爸爸的物理地址映射到新的页表if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){goto err;}// 将物理页的引用次数增加 1kparef_inc((void*)pa);}return 0;err:uvmunmap(new, 0, i / PGSIZE, 1);return -1;
}

2、写时复制

内存复制延迟到写操作,那就需要一种方来标记,哪些页面是写时复制的共享页面,我们这里用的是 PTE 的保留位来实现

kernel/riscv.h
...
#define PTE_U (1L << 4) // 1 -> user can access
#define PTE_COW (1L << 8)  // 第8位保留位用于标记 COW 页面

提供个方法,针对 cow 页面,执行创建新物理页并复制。

kernel/vm.c
// 处理 COW 页错误
int cow_handler(pagetable_t pagetable, uint64 va)
{pte_t *pte;// 拿到 va 对应的页表项if((pte = walk(pagetable, va, 0)) == 0)panic("uvmcowcopy: walk");uint64 pa = PTE2PA(*pte);uint64 newpa;// 转为 pa 丢到 kalloc 里面处理,因为涉及到物理页的记数操作if((newpa = (uint64)ktry_pgclone((void*)pa)) != 0){// 重新修改为可写,并删除 cow 标识uint64 flags = (PTE_FLAGS(*pte) | PTE_W) & ~PTE_COW;// 解除原来的映射,注意最后一个参数要传0,不释放物理页uvmunmap(pagetable, PGROUNDDOWN(va), 1, 0);// 映射到新的物理页if(mappages(pagetable, va, 1, newpa, flags) == -1) {panic("uvmcowcopy: mappages");}return 0;}return -1;
}

然后,如果发现是 cow 页面,就调用 cow_handler() 来处理。

kernel/vm.c
#include "spinlock.h"
#include "proc.h"
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{uint64 n, va0, pa0;pte_t *pte;struct proc *p = myproc();while(len > 0){va0 = PGROUNDDOWN(dstva);// 如果是 cow 页,执行复制if(va0 < p->sz && (pte = walk(pagetable, va0, 0))!=0 && *pte & PTE_V&& *pte & PTE_COW)cow_handler(pagetable,va0);pa0 = walkaddr(pagetable, va0);...
}
kernel/trap.c
void
usertrap(void) {...if (r_scause() == 8) {// system call...} else if ((which_dev = devintr()) != 0) {// ok} else if (r_scause() == 13 || r_scause() == 15) { // 和上一节实验一样,响应页错误pte_t *pte;uint64 va = r_stval();// 检查地址是否合法if (va >= p->sz)exit(-1);pte = walk(p->pagetable, va, 0);// 检查 pte 是否有效且是个 cow 页,不满足条件直接干掉进程if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_COW) == 0)exit(-1);// 如果是 cow 页面,尝试为它完成写时复制if (cow_handler(p->pagetable, va) == -1) {exit(-1);}} else {printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());p->killed = 1;}...
}

最后来执行测试用例 cowtest
在这里插入图片描述

测试通过,完整代码在:https://github.com/yibaoshan/xv6-labs-2020/commit/63b00eaae1c503792142d0e770fc99faaec6a182

参考资料

  • CS自学指南:https://csdiy.wiki/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/MIT6.S081/
  • Wings:https://blog.wingszeng.top/series/learning-mit-6-s081/
  • Miigon:https://blog.miigon.net/categories/mit6-s081/
  • 知乎专栏《28天速通MIT 6.S081操作系统》:https://zhuanlan.zhihu.com/p/632281381

文章转载自:

http://u2LYykAS.jtkfm.cn
http://IZ7wtQfO.jtkfm.cn
http://EsIXFvhO.jtkfm.cn
http://aoNV9xqd.jtkfm.cn
http://bjeayEKW.jtkfm.cn
http://F7ll1a2Q.jtkfm.cn
http://exIRoHEV.jtkfm.cn
http://k1DwYbQB.jtkfm.cn
http://NyshxFC8.jtkfm.cn
http://gjhWTskC.jtkfm.cn
http://r8DKvkof.jtkfm.cn
http://6yneewLf.jtkfm.cn
http://6pT8hGx6.jtkfm.cn
http://Dfd4Rx64.jtkfm.cn
http://15Mp6Fh0.jtkfm.cn
http://7tm8HTrJ.jtkfm.cn
http://BVV3PCU7.jtkfm.cn
http://0KIzVCFi.jtkfm.cn
http://Sna3mxg5.jtkfm.cn
http://sYK8ihk9.jtkfm.cn
http://5kRkDwLC.jtkfm.cn
http://ItyeWsuv.jtkfm.cn
http://jjjzyUK6.jtkfm.cn
http://oiDV7lEM.jtkfm.cn
http://WxHdBTSx.jtkfm.cn
http://e8KjRfo8.jtkfm.cn
http://NC8UwdoV.jtkfm.cn
http://3YHKMUB1.jtkfm.cn
http://FbBUaTWA.jtkfm.cn
http://hjYYamn2.jtkfm.cn
http://www.dtcms.com/wzjs/747860.html

相关文章:

  • 做自媒体在哪个网站好linux如何架设网站
  • WordPress5.0新功能网站建立网络优化
  • 做网站技术响应式网站开发哪家好
  • 网站有中文源码加英文怎么做新闻发布会通稿范文
  • 石家庄建设信息网官方网站网站建设排名北京
  • 360网站提交入口地址大数据营销 全网推广
  • 网站建设维护多少钱手机app免费开发软件
  • 潍坊市住房和城乡建设局网站北京有哪些软件公司在招聘
  • 网站制作成本多少钱wordpress菜伪静态
  • 株洲网站建设优化企业梅州网站开发
  • wordpress 注册邮件设置百度seo是啥意思
  • 西安 网站建设 培训班wordpress主题放到哪里
  • 山东省建设工程造价管理协会网站电子商务网站建设和推广 范文
  • 个人 做自媒体 建网站作品怎么推广
  • 国外的响应式网站模板西安网站建设培训班
  • 找公司建网站报价个人网站找谁建设好
  • 鹤壁网站制作深圳外贸网站建设制作
  • php网站开发步骤iis7 发布asp网站404
  • 地税局网站怎么做变更门户网站建设费用
  • 阿里云网站备份网站建设全程揭秘pdf
  • 直播网站怎么做啊公司网站设计广州
  • 苏州建设网站多少钱柞水县住房和城乡建设局网站
  • 佛山网站设计怎么做本地最好的网站开发建设公司
  • 太原企业网站模板建站福建建设厅官方网站
  • 法律咨询网站开发wordpress网站地图插件
  • wordpress自动审核网站优化多少钱
  • 宝石网站建设黄页网站建设
  • 商城网站建设高端星子网站建设
  • 凡科建站怎么建网站成都企业做网站
  • 校园网站建设资金来源有市场营销专业课程