我以前一直想不明白:为什么我一个小小散户竟能左右整个股市?不管之前涨势多么疯狂,我一买入它必定下跌!我一卖出它就上涨。我一空仓大盘疯涨,我一满仓大盘狂泻。手握百亿资金的庄家们竟死死盯着我手里这几万块钱不放。这到底是为啥?
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内核》,笨叔出品,笨笨的味道,总有你想要的!

[往期精彩]
继续阅读
阅读原文