查看原文
其他

[笨叔点滴10] 中断到“底”来了吗?

小笨叔 奔跑吧Linux社区 2019-04-24

 我以前一直想不明白:为什么我一个小小散户竟能左右整个股市?不管之前涨势多么疯狂,我一买入它必定下跌!我一卖出它就上涨。我一空仓大盘疯涨,我一满仓大盘狂泻。手握百亿资金的庄家们竟死死盯着我手里这几万块钱不放。这到底是为啥?



A股让我琢磨不透,但是在计算机里,中断和进程也是让人琢磨不透?比如某个微信群里讨论问题:在非抢占Linux内核中,为啥中断发生在内核态的时候不去抢占? 



这个问题明显就是中断和进程之间的那些扯不清楚的事情。为啥在Linux 2.4内核里没有实现中断抢占呢? 其实大家都是从现在Linux 4.x内核的眼光来看老版本的内核。要知道LInux内核也是90后哟,它诞生于 91年,现在才27岁。



关于中断和进程之间那些事,笨叔觉得如下几个问题挺有意思

  1. 中断发生时候,ARM处理器究竟帮你做了那些事情?

    [大家可以见《奔跑吧Linux内核》第618~ 625页]  



   2. 如果中断发生在内核态,它的中断上下文 究竟存放在什么地方?有那些寄存器需要存?或者说那些寄存器是主演,那些寄存器其实是配角?

        [参考第625页这个图] 这个问题,大家需要搞清楚,IRQ栈和SVC栈究竟存了些啥东东,那些寄存器是必须的,也就是主角,没有它不行。那些寄存器其实跑龙套的,有没有不伤大雅。




        3.  如果中断发生在用户态,它在中断处理完成之后,它是怎么返回到用户空间?

        [这个问题,大家可以去看汇编,这个在《奔跑吧》里没有去详细分析这个__irq_usr这个汇编函数,这个函数不复杂,大家可以自己去阅读]


      4. 假设时钟的tick中断来了,而且它发生在用户空间,硬件中断完成之后,检查现在需要调度,那么调度到下一个进程next运行,假设这个next进程也是用户进程,那么这个next进程究竟从什么地方开始执行?


    [这个问题,其实很有意思,假设A用户进程在B这个地方,发生了中断,之后,又发生了调度。那如果一段时间之后,A进程又被调度回来,它是不是从B这个地方开始执行呢?


    要搞清楚这个问题,大家可以看《奔跑吧linux内核》第369~374页的描述,也可以参考这个图。其实关键点是在switch_to函数的实现和理解上]。


    switch_to()函数如果简单的总结的话,其实两条语句就够了。如下面:

    cpu_switch_to:

    stmia r0!, {r4 - sl, fp, sp, lr}  @store regs on stack

    ldmia r1, {r4 - sl, fp, sp, pc}   @load all regs saved previously


    假设r0指向prev进程的cpu_context数据结构,r1指向next的cpu_context数据结构。


    第一条汇编把prev进程的sp和lr寄存器保存到r0指向的cpu_context里,然后把next进程中cpu_context里的sp和lr寄存器装载在 CPU硬件的寄存器里,就这么简单完成了 进程上下文切换。完成切换之后,next进程就从ldmia这条指令下一条指令开始运行了,真的哟,真的开始运行了。。。


    小明疑惑的说:笨叔,我怎么能验证你说的鬼话呢?

    笨叔:其实很简单,你用笨叔的“O0”内核来debug单步一下,你可以在switch_to函数里设置断点,然后观察prev和next进程的cpu_context里面的lr都装了啥值,

    小明:唷,好办法,我就去试试

    笨叔:同时可以可以把prev和next的sp栈打印出来看看哟

    小明:好嘞,笨叔


    cpu_context是啥什么鬼,小伙伴可以看第342页的copy_thread()函数里,进程第一次被创建的时候cpu_context里究竟装了什么葫芦。



    估计有小伙伴对pt_regs和cpu_context这两个数据结构玩意搞糊涂了吧,其实如果,你把这两个数据结构的用意和用途想明白了,上述这个问题都不是问题。pt_regs是保存当前进程发生中断或者异常或者系统调用等情况的时候CPU的上下文,它是寄居在进程内核栈的顶部。而cpu_context算是PCB的核心保存成员,PCB是啥?不是电路板,是进程核心控制块。cpu_context只是用来保存进程切换时候的CPU状态,其实就是SP和LR有用,他们俩个是主角。


    今天笨叔废话一大堆,呵呵。笨叔弱弱问一句,我的中断来了,A股的“底”到底到木有?欢迎小伙伴在评论区留言,到“底”来了没?


    最后,大家记得关注笨叔的书和配套视频,《奔跑吧linux内核》,笨叔出品,笨笨的味道,总有你想要的!



    [往期精彩]

    [旗舰篇] 第一季旗舰篇资料汇总

    [笨叔点滴1] 为什么do_page_fault函数里代码需要判断用户态还是内核态?

    [笨叔点滴2] 为啥子ARM32体系结构中每个处理模式都有一个单独的栈?

    [笨叔点滴3] “栈”谁便宜了?

    [笨叔点滴4]“栈”谁便宜了2

    [笨叔点滴5] git rebase和git merge究竟有啥区别?

    [笨叔点滴6] 叔,这个git咋玩啊?

    [笨叔点滴7] 再也回不去的C语言

    [笨叔点滴8] GNU C语言的扩展

    LinuxCon 2018北京游记(1)

    LinuxCon2018北京笨叔笨游记 2

    《奔跑吧linux内核》配套资源迁移到码云上

    考点来了:4月18号视频更新

    代码导读之如何使用qemu来单步调试head.S

    代码导读之内存管理初始化 - 启动汇编

    视频更新:内存管理代码框架导读

    DMA那些事儿

    私密VIP群答疑

    高级运维必杀技:如何图形化单步调试RHEL/Centos 7里的内核?

    首发:Meltdown漏洞分析与实践

    [奔跑吧Linux内核] 故乡

    致敬Beyond

        您可能也对以下帖子感兴趣

        文章有问题?点此查看未经处理的缓存