首页 > 其他分享 >xv6 磁盘中断流程和启动时调度流程

xv6 磁盘中断流程和启动时调度流程

时间:2023-12-23 22:31:49浏览次数:32  
标签:sched 中断 流程 xv6 进程 磁盘 上下文 ptable

本文讲述 xv6 中的一些细节流程,还有对之前文中遗留的问题做一些补充说明,主要有以下几个问题:

  1. 一次完整的磁盘中断流程
  2. 进入调度器后的详细流程
  3. sched 函数中的条件判断
  4. scheduler 函数中为什么要周期性关中断

一次完整的磁盘流程

此节讲述完整的磁盘读写流程,读写的流程总体差不多,这里以读为例子,先看“流程图”(看代码时的笔记图)

xv6 磁盘中断流程和启动时调度流程_linux

read
    int $T_SYSCALL
        sys_read
            fileread
                readi
                    bread
                        bget
                        iderw
                            idestart

还是从 A 进程的用户态 read 函数开始:

  1. A 进程用户态调用 read 读取磁盘上的数据
  2. read 通过 INT 0x80 软件中断,通过中断门进入内核,此时会关中断(NOTE 这里我以中断门来实现系统调用为例,会关中断,xv6 源代码是以陷阱门实现系统调用,不会关中断)
  3. 期间多次取锁放锁,进行了多次 pushcli 和 popcli,但总是成对存在,所以目前总体还是处于 0 次 puchcli 状态
  4. 如果磁盘数据没有缓存,调用 iderw 来读写磁盘

A 进程内核态,iderw 函数:

  1. acquire(&idelock),获取磁盘锁,pushcli,cpu.IF = 0,1 次pushcli 状态
  2. 调用 idestart,将要读写的命令,扇区号等信息写进磁盘端口,以此来请求磁盘操作。写磁盘端口是通过 out 指令实现的。向磁盘发送命令后,磁盘就会工作,磁盘完成工作后就会向 cpu 发送中断信号。
  3. A 进程调用 sleep 等待磁盘操作完成。在 sleep 函数中,获取 ptable.lock,释放 idelock,然后调用 sched 让出

by the way,这里补充说明 sched 函数中的条件检查,之前的文章都一笔带过了:

void sched(void)   //让出CPU,重新调度
{
  int intena;
  struct proc *p = myproc();

  if(!holding(&ptable.lock))      // 必须持有 ptable.lock
    panic("sched ptable.lock");
  if(mycpu()->ncli != 1)          // 1 次 pushcli 状态
    panic("sched locks");
  if(p->state == RUNNING)         // 只可能是 SLEEPING、RUNNABLE、ZOMBIE 三种状态之一
    panic("sched running");
  if(readeflags()&FL_IF)          // 此时肯定处于关中断状态(通过中断门进入内核会关中断,1次pushcli状态也应该对应关中断状态)
    panic("sched interruptible");
  intena = mycpu()->intena;
  swtch(&p->context, mycpu()->scheduler);
  mycpu()->intena = intena;
}

sched 函数中有 4 个条件检查:

  1. xv6 是个多 CPU 多任务系统,在 sched 任务调度的时候,需要持有 ptable.lock,不然进程的上下文会发生紊乱,举个简单的例子,A 时间片到了,先将 A 的状态设置为 RUNNABLE,然后调用 sched 让出 CPU,如果此时没有持有 ptable.lock,那么 A 进程便可能在另一个 CPU 上被调度,那么便出现一个进程在两 CPU 上运行的情况,Error
  2. 在 sched 函数中应当只有 1 次 pushcli 状态,这个条件检查感觉有点难以理解。从实践看代码确实,不管从哪条路径到达 sched 函数,都应该只有 1 次 pushcli,这是获取 ptable.lock 的锁造成的。从个人理解上说,sched 是为了调度进程,是要从 A 进程到 B 进程,那么 A 进程的开关中断(pushcli popcli 次数)不应该带入 B 进程,除了一种情况——调度,那就是 A 进程获取 ptable.lock 但是要在 B 进程中释放 ptable.lock。所以 sched 中应当只有 1 次 pushcli
  3. 在真正切换进程上下文之前,会首先修改旧进程的状态,在 xv6 中是 SLEEPING、RUNNABLE、ZOMBIE 三种之一
  4. 在 sched 中理应处于关中断状态,如果是通过中断门进入内核的,那么本身就处于关中断。如果是通过陷阱门进入内核,那么有 1 次 pushcli,也会处于关中断状态

回到磁盘中断,当 A 进程调用 sched 切换到 B 进程,这里假如 B 进程最初是因为时间片到了,调用 yield->sched->swtch 主动让出 CPU 的,则 B 进程的流程如下:

  1. 回到 B 进程 sched 函数中的 swtch 下一条指令处,然后释放 ptable.lock,此时 cpu.IF = 0,0 次 pushcli 状态,cpu.IF = 0 仍然处于关中断状态 是因为 A 进程通过中断门进入内核关中断造成的
  2. B 进程经过一些列指令后,最后执行 iret 返回 B 进程的用户态,此时会开中断
  3. NOTE,这里我们假设 CPU 内部逻辑:每条指令执行后都会检查是否有中断发生,如果有中断发生且开中断的情况下,则去处理中断。再假设,此前的磁盘操作已完成,已经向 CPU 发生了中断信号。但是在此之前 CPU 一直没有去处理中断,是因为在此之前一直处于关中断状态。
  4. Now,CPU 处于开中断状态,继续执行 B 进程的指令,开中断后的第一条指令执行完成后,检查是否有中断发生,发现有磁盘中断,那么中断 B 进程,通过中断门进入内核(该过程关中断)
  5. 执行磁盘中断处理程序,也就是执行 insl 指令从 0x1f0 端口将磁盘数据读取到内存,然后唤醒等待该磁盘事件的进程,在我们的例子当中就是 A 进程
  6. 中断执行完成,iret 返回 B 进程用户态(该过程开中断)
  7. 继续执行 B 进程的指令
  8. 时钟中断 B 进程,再次通过中断门进入内核(关中断),发现 B 进程的时间片到了,那么调用 yield->sched->swtch 重新调度进程,这里假设调度到 A 进程

回到 A 进程的内核态,准确来说回到 iderw->sleep->sched->swtch 的下一条指令

  1. A 进程执行 release(ptable.lock)、acquire(idelock)、release(idelock),此时状态: cpu.IF = 0,0 次 pushcli
  2. 将磁盘中断获取的数据 cp 到 A 进程内核态
  3. A 进程层层返回
  4. 最后 iret 返回 A 进程用户态(开中断)

系统启动进入调度器后的流程

xv6 磁盘中断流程和启动时调度流程_操作系统_02

main
    userinit //准备好 initcode 进程
    mpmain
        scheduler  // 进入调度器

调度器上下文:

  1. 第一次进入 scheduler,for 循环找到 RUNNABLE 进程,目前就只有一个 initcode 进程为 RUNNABLE 进程,找到并切换上下文到 initcode 进程

initcode 进程上下文:

  1. 执行 forkret 函数,因为是第一次执行,会首先执行 iinit 来初始化根文件系统
  2. 执行 readsb 从磁盘中读取超级块数据,期间会使用 iderw 读写磁盘,具体流程见第一小节。总之,initcode 进程会调用 sleep 函数让出 CPU 来等待磁盘操作
  3. 在 sleep->sched->swtch 中再次切换上下文到 调度器上下文

调度器上下文:

  1. 切换到内核页表,然后遍历任务队列,寻找 RUNNABLE 进程,但是目前只有一个且处于 SLEEPING 状态的进程,所以这里调度器会轮询空转,直到磁盘中断处理完成,initcode 进程被唤醒。
  2. 再次切换上下文到 initcode 进程

initcode 进程上下文

  1. 回到 forkret->iinit->readsb->bread->iderw->sleep->sched->swtch 的下一条指令处,然后层层返回到 forkret
  2. 再执行 initlog 恢复日志,这里会涉及到两次磁盘读写,道理同上,不再赘述
  3. 第 4 次调度到 initcode 进程后,forkret 函数执行完毕,再执行 trapret 函数,其中包含了 iret 指令,至此回到用户态,开始执行 initcode 进程的逻辑

by the way again,这里解释为什么在 scheduler 函数中需要周期性的开中断:

void scheduler(void)
{
  for(;;){
    sti();    // 周期性开中断

    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){  //循环找一个RUNNABLE进程
        ...
    }
    
  }
}

进入调度器上下文有两条路径:

  1. 系统刚启动进入 scheduler
  2. sched 函数中 swtch 上下文到调度器

回想前面说的 sched 函数,在它切换到新进程并返回用户态之前理应都处于关中断的状态。而一直处于关中断且没有开中断的话会引发死循环。

举个例子,假设没有周期性的开中断,也就是 scheduler 代码长这样的话:

void scheduler(void)
{
  for(;;){
    // 遍历进程列表,寻找 RUNNABLE 进程
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
        ...
    }
  }
}

假如当前系统只有一个进程(shell进程),它需要等待键盘输入而被阻塞(state==SLEEPING),内层循环是找不到 RUNNABLE 进程的,便回到外层循环,外层循环现在相当于什么也不做,便又再次进入内层循环。如此下来死循环。

而加入周期性的开中断后,CPU 便会响应中断。当有键盘输入时,中断当前的调度上下文而进入中断上下文,执行键盘中断处理程序,唤醒 shell 进程,中断处理完成后再回到调度上下文。此时内层循环便能找到一个 RUNNABLE 进程,然后切换到它的上下文执行。

本文就先补充这么多吧,这补充系列的文章是之前做了关于 xv6、nemu 的项目,将 xv6 启动到 nemu 上,这需要对很多地方细扣,对 xv6 的理解又增加了一些,分享出来。

停更这么久啊,一直再忙工作,学习新的东西,时间不是很多,当然也有懒的原因,后面慢慢克服回归吧。OK,那有什么问题欢迎来讨论交流。


标签:sched,中断,流程,xv6,进程,磁盘,上下文,ptable
From: https://blog.51cto.com/u_15193561/8947275

相关文章

  • 磁盘性能检测(time&&fio)
    一、time命令:timeddif=/tmp/test1of=/tmp/test2bs=8kcount=51200oflag=dsync参数说明:1、time有计时作用,dd用于复制,从if读出,写到of;2、if=/dev/zero不产生IO,因此可以用来测试纯写速度;3、同理of=/dev/null不产生IO,可以用来测试纯读速度;4、将/tmp/test1拷贝到/tmp/te......
  • 神经网络量化流程(第一讲TensorRT)
    TensorRT量化工具,支持PTQ和QAT量化基本流程:读取模型-》转化为IR进行图分析,做一些优化策略一、TensorRT量化模式TensorRT有两种量化模式:分别是implicitly以及explicitly量化,前者是隐式量化,在7.0及之前版本用的较多;后者显式量化在8.0版本后才完全支持,就是可以加载带有QDQ信息的模......
  • Linux磁盘分区和挂载
    一、准备工作(1)查看主机磁盘命令:lsblk(2)查看主机磁盘挂载文件系统情况命令:df-h二、磁盘分区(1)分区命令:fdisk-b1024/dev/vda其中:b1024,一个sectorsize的大小;1GB;使用-b指定sector时,每个sector的大小是:sectorsize(512,1024,2048or4096)。(2)根据提示填写相应信息n,是......
  • JAVA云his系统、门诊、住院业务使用流程知识总结
    云HIS系统是一款满足基层医院机构各类业务需要的健康云系统。系统能帮助基层医院机构完成日常各类业务,提供病患挂号支持、病患问诊、电子病历、开药/发药、会员管理、统计查询、医生站和护士站等一系列常规功能,还能与公卫、PACS等各类外部系统融合,实现多层机构(医院)之间的融合管理。......
  • 2.7 Metallic与Speculer流程及相互转换
    一、PBR流程金属/粗糙度和高光反射/光泽度工作流程通用贴图:法线贴图(normalmap)AO贴图(ambientocclusionmap)高度贴图(heightmap)1.金属度/粗糙度工作流(常用)BaseColorRGB贴图-sRGBBaseColorRGB贴图-sRGB储存数据:非导体(电介质)的漫反射色/反照率颜色(DiffuseReflectedColor/Albedo)......
  • [贴装专题] 视觉贴装平台与贴装流程介绍
    作者:丶布布视觉贴装平台介绍平台的贴装流程:将下视相机(DownLook)移至补强片贴装位置;目的:通过下视相机拍照,=补强片贴装位置中心的实际物理坐标;再将下视相机(DownLook)移至左侧补强片进料位置,拍照补强片;目的:通过下视相机拍照,计算左侧进料处的补强片的实际中心坐标,便于吸嘴吸取;根据......
  • YARN集群中应用程序的执行流程
       Hello,各位“极客”好,上一篇文章中介绍了YARN集群架构的基本内容,那么,在YARN集群中应用程序的执行流程是怎样的呢?这个问题很重要,就要好好说道说道了......    客户端提交应用程序(可以是MapReduce程序、Spark程序等)到ResourceManager。ResourceManager分配用于运......
  • 1-4时间序列数据建模流程范例
    0.配置importtorchprint('torch.__version__=',torch.__version__)"""torch.__version__=2.1.0+cpu"""importos#mac系统上pytorch和matplotlib在jupyter中同时跑需要更改环境变量#os.environ["KMP_DUPLICATE_LIB_OK"]=&q......
  • 磁盘io问题排查
    环境:OS:Centos7 1.top查看wa很高avg-cpu:%user%nice%system%iowait%steal%idletop-08:45:04up722days,17:33,1user,loadaverage:3.28,3.12,3.09Tasks:143total,1running,142sleeping,0stopped,0zombie%Cpu(s):0.0us,0......
  • 性能测试流程与设计
    性能测试流程 性能测试准备 测试分析与设计 性能测试环境搭建 ......