Q: linux支持中断嵌套吗?
A:以前支持,现在不支持。当ARM处理器收到中断的时候,它进入中断模式,同时ARM处理器的CPSR寄存器的IRQ位会被硬件设置为屏蔽IRQ。
原因是可能会出现同一时间大量中断,如果嵌套可能会造成stack溢出等危险。
裸机流程: ①、使能中断,初始化相应的寄存器。 ②、注册中断服务函数,也就是向 irqTable 数组的指定标号处写入中断服务函数 ②、中断发生以后进入 IRQ 中断服务函数,在 IRQ 中断服务函数在数组 irqTable 里面查找 具体的中断处理函数,找到以后执行相应的中断处理函数。新的中断机制,顶底半部。
我们在使用 request_irq 申请中断的时候注册的中断服务函数属于中断处理的上半部,只要中断触发,那么 中断处理函数就会执行。而下半部则负责处理比较费时的,对时间要求不敏感的任务。
Linux 内核将中断分为上半部和下半部的主要目的就是实现中断处理函数的快进快 出,那些对时间敏感、执行速度快的操作可以放到中断处理函数中,也就是上半部。剩下的所 有工作都可以放到下半部去执行,比如在上半部将数据拷贝到内存中。
而下半部处理分为三种: 1、软中断softirq_vec我把它叫做软中断动作响应向量表>_<,记录的相应action的种类
struct softirq_action { void (*action)(struct softirq_action *); }; static struct softirq_action softirq_vec[NR_SOFTIRQS]; enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, BLOCK_IOPOLL_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, RCU_SOFTIRQ, NR_SOFTIRQS }; NR_SOFTIRQS = 10;
软中断必须在编译的时候静态注册,上半部可以打断软中断,有数量限值最大32个,过多会影响内核效率,因为其是轮询处理。
2、tasklettasklet是通过软中断实现的,所以它本身也是软中断。Tasklet采用无差别的队列机制。
(1)无类型数量限制; (2)效率高,无需循环查表; (3)支持SMP机制; 它的特性如下: 1)一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行。 2)多个不同类型的tasklet可以并行在多个CPU上。
struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; }; void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); 函数参数和返回值含义如下: t:要初始化的 tasklet func:tasklet 的处理函数。 data:要传递给 func 函数的参数 void tasklet_schedule(struct tasklet_struct *t)
下半部相应*func参数同样为(unsigned long),可以放自定义的设备指针值。
3,工作队列可打断,可阻塞。上面两个运行与中断上下文,不可阻塞,而工作队列则是内核的一个线程。
关于Linux中断
多个中断可以放在一个线程中,也可以每个中断分配一个线程。我们用结构体workqueue_struct表示工作者线程,工作者线程是用内核线程实现的。
而工作者线程是如何执行被推后的工作——有这样一个链表,它由结构体work_struct组成,而这个work_struct则描述了一个工作,一旦这个工作被执行完,相应的work_struct对象就从链表上移去,当链表上不再有对象时,工作者线程就会继续休眠。
struct work_struct { atomic_long_t data; struct list_head entry; work_func_t func; }; struct workqueue_struct { struct list_head pwqs; struct list_head list; ... struct worker *rescuer; ... } struct worker { union { struct list_head entry; struct hlist_node hentry; }; struct work_struct *current_work; work_func_t current_func; struct pool_workqueue *current_pwq; ... ... struct workqueue_struct *rescue_wq; };
使用起来bool schedule_work(struct work_struct *work)更温和,可阻塞,对时间更不敏感。