不落辰

知不可乎骤得,托遗响于悲风

0%

地址映射关系 即 va -> pa 的 映射

  • 在做本实验之前,xv6的虚拟内存机制如下

    • 对于kernel , 内核只有一张全局的kernel pagetable. 所有kernel thread 共用这一张pagetable. 通过MMU使用.
    • 对于user , 每个user process的user thread 有一张user pagetable. user通过MMU使用.
    • 但对于user传入kernel的va,kernel该如何使用user pgtbl来进行寻址呢 ? kernel 通过软件模拟(walkaddr)来查询user pgtbl 来进行user va的寻址.
      • 很显然,效率很低 不如硬件. 现代操作系统采用的也并非是这种机制.
  • 本实验 : 那么 为了让kernel可以直接通过硬件MMU来使用user pagetable. 我们实现如下措施

    • (以下就是所谓的将内核页表和用户页表合并)
      • 一个process的kernel thread 都 分配一个 pagetable.
      • 且在这个kernel thread pgtable
          1. 不但维护了kernel 的地址空间映射
        • 2. 还要 维护user thread的user pgtable的地址空间的映射(va->pa)
      • 对于1. 我们应当 为 每个kernel thread pgtbl建立和 全局 kenrel pgtbl 基本一样的地址映射关系 (kvminitproc)
      • 对于2. 我们应当 将user thread pgtbl 的维护的地址映射关系 拷贝到 kernel thread pgtbl 的 [0,0XC00..00-1]处
        • 并在 user thread pgtbl 的地址映射关系发生改变时(pte的增加/删除/修改),即时拷贝到kernel thread pgtbl上
    • 合并之后,kernel 使用 user va的方式 就是 直接通过MMU在kernel thread pgtbl的user部分进行查询. 而不用通过walkaddr,提高效率
  • 下图就是一个合并user部分后的kernel thread pgtbl

  • 本实验后,xv6的虚拟内存机制如下

    • 3个pgtbtl
      • 全局 kernel pgtbl (kernel的scheduler thread用)
      • user thread pgtbl (user thread用)
      • kernel thread pgtbl(包含user部分) (kernel 用)
    • 主流的OS也是用这种方法.
  • 关于 vm.c 注释见文

  • 关于虚拟内存是否连续见文末

阅读全文 »

  • part 2 : 利用栈桢,打印函数调用.
  • part 3 : 为xv6增加sys_sigalarm和sys_sigreturn系统调用
    • sys_sigalarm : 注册callback以及超时时间
    • tick Interrupt : tick超时,返回user到callback
    • sys_sigreturn : user callback 结束. 通过该syscall 返回之前被tick超时打断的pc
    • 实现重点是 在tick超时时 将 trapframe 进行备份,再返回user执行callback. 当user callback结束sys_sigreturn时,再将之前的trapframe替换出来.
      • 最主要原因是trapframe里面保存了epc(user进入kernel前的指令地址),kernel返回user时一般pc返回到epc+4
      • 所以要通过备份trapframe,来保证callback结束后可以返回到user正确的pc
阅读全文 »

本文介绍xv6的trap流程

  • user空间和kernel空间的切换称为trap

    • xv6 系统调用 是如何在user和kernel空间进行切换的 ?
  • 关键步骤及指令如下

    • user ecall
      • 提高程序的权限 , 保存当前地址($sepc) , 记录trap原因(r_scause()) , 跳转到trampoline
    • trampoline uservec
      • 将cpu reg中user的上下文保存进trapframe,如user stack pointer , return addr 等; 并将 kernel thread的上下文聪trapframe加载进cpu reg. 如kernel stack pointer , func to jump , kernel pgtbl($satp). 然后跳转到usertrap()
    • usertrap
      • 根据陷入kernel的原因($scause),执行动作如syscall().
    • usertrapret
      • 即将离开kernel , 将kernel上下文保存进trapframe , 以便下次陷入内核时trampoline将其加载进来. 跳到userret
    • trampoline userret
      • 切换到 user pagetable , 将user上下文从trapframe加载进来. 跳转回user($sepc)
    • user ret : 跳到user程序的下一指令
  • 之前有人问我个问题hhh,当复习了。

    • 从用户到内核需要的寄存器哪些会发生改变啊?
    • 答:
    • 比说ecall吧. 他得改变代表权限的reg,从user mode改成supverisor mode ; 还得改变保存$PC到$sepc reg.;还得设置$scause reg代表trap的原因;进入trampoline的uservec之后,得把之前user态时候cpu上的reg保存进内存,然后将该process的kernel thread的上下文加载到cpu的reg上. 比如说kernel stack pointer加载到$sp ; 还得改变$satp,切换成kernel pagetable来切换地址空间,

阅读全文 »

  • 操作系统就是一个中断处理程序
    • 负责将第一个进程加载完后 第一个进程通过fork execve exit一系列系统调用创建其他的
    • 创建状态机 : fork
    • 替换 : execve
    • 终止 : _exit
      • 请问main退出后的detached thread的行为 ?
阅读全文 »

将loop和thread结合在一起的类 : EventLoopThread. one loop per thread

阅读全文 »

weak_ptr的使用 : 延长TCPConnection生命周期,防止channel->handleEvent时被析构

阅读全文 »

  • 并发bug 之 数据竞争 Data Race

    • 不同的线程同时访问同一段内存,且至少有一个是写
    • 为处理Data Race,我们需要一个互斥的协议,而peterson这种纯软的算法,太难了。故 我们应当使用(互斥)锁 消灭datarace
  • ThreadSanitizer原理

    • 不同线程对一块共享内存操作 且至少有一个是写。对这些动作的执行顺序进行排序,若检验出无法排序的(即排序结果不唯一),则error
  • 学习自jyy
阅读全文 »