中断与异常详解(五)
随着看的东西的增多,之前不明白的地方也开始有了眉目,所以更新前几节的东西,欢迎指正。想想马上就中断返回,进入进程描述了,还是挺激动的呢。
不得不推荐一篇写得很好的文章《spinlock的剖析与改进》
http://www.searchtb.com/2011/06/spinlock%E5%89%96%E6%9E%90%E4%B8%8E%E6%94%B9%E8%BF%9B.html
中断向量表多达256项
虽然默认使用的只有49条,但很明显中断服务程序必须支持SMP,这也是在第三节为什么在 handle_IRQ_event(irq, ®s, action);对中断进行实际处理之前会放弃多cpu锁,那么这段代码自然就是多cpu可重入的了。但因为action是在有多cpu锁的状态下获得的,所以就只会有一个获取成功的cpu去响应这条中断线。
软中断向量表只有32项
默认只是用了4项,并将2.4之前版本的bh机制封装到了0号软中断线上。
两者其实有很多共通的地方
中断前半部分分为32项cpu内部异常,与224项外部硬中断。
其中0-31号cpu内部异常直接由自身处理了,不需要对中断线进行管理,因为中断线是多cpu共享的公共资源。
32-225号硬中断线则是公共资源,需要每个cpu先去获得处理权限,才能对中断线上的中断请求予以响应。
同样的软中断向量表也是公共资源,其设计初衷更理想,每个cpu不用申请就可以直接去处理,但这对代码设计要求太高,所以才有tasklet机制去限制。
bh_task_vec[32]跟硬中断线很像
设计为任意时刻每个bh_task_vec最多只能跑在一个cpu上,但多个cpu可以跑多个bh_task_vec。硬中断线通过锁cpu,关中断来保证一个cpu只能响应一条硬中断线,多个cpu可以响应多条中断线,中断线不被重复申请;而tasklet机制通过对tasklet_struct结构体中的state状态量标记是否已被调度来保证每个bh_task_vec在任意时刻只能被调度到一个cpu的0号软中断服务队列中,多个cpu有多个0号软中断服务队列,两种不同的处理方式实现了同样的公共资源分配与共享。
硬中断线是在获得多cpu锁的情况下获取中断服务队列并执行,所以多个cpu竞争这把自旋锁,谁获得锁谁就响应;而tasklet机制是在获得tasklet_struct中的调度权限之后将bh_task_vec调度到某个cpu并执行,所以多个cpu竞争的是调度权限,谁有调度权限谁就拿走这个bh_task_vec(不是真正的取走,只是链接过去而已)。
这种同步模型可以总结为n:n生产者-消费者问题
多个生产者产生多种中断请求,单个生产者不允许重复产生,就关了单个生产者的中断线,多个消费者竞争响应中断,可以理解为所有消费者都接到了通知,但需要在一个全局锁中去拿中断服务队列,拿不到的就各回各家,拿到就响应。全局锁在硬中断中就是多cpu锁,在tasklet中就是每个tasklet_struct中的调度权限。
不理解的地方归纳如下:
1、中断嵌套到底是个何其神奇的东西?怎么发生的?硬中断线上的8个状态到底如何改变,对应什么状态?
2、每个cpu的状态数据结构中断的软中断缓存任务有何作用?Tasklet_struct中的state状态量的TASK_STATE_RUN状态有何作用,获取这把锁失败时候重新调度是几个意思?没想明白tasklet_trylock(t)失败之后的流程。
3、spinlock自旋锁的汇编,因为源代码中要穿插其他节的东西,而且编译之后有变化,所以理解困难。
4、看见多处对eflags进行保存,用意何在?
还有很多,有空再说。
中断返回
ret_from_intr, ret_from_exception, ret_from_sys_call根据之前压栈的EFLAGS和CS段信息先去判断是否需要返回用户态,其中ret_from_sys_call需要再关一次中断,并重新调度进程,看是否有信号等待处理,最终返回。
如果ret_from_sys_call,不调度,没有信号量,不就直接RESTORE_ALL了?那在哪儿开中断呢?