linux中断分层技术
为什么要中断分层?
中断嵌套
1.当一个中断处理的时候,发生另一个中断。
2.如果是慢速中断:
(1)同类型的中断会被忽略
(2)不同类型的会被响应
3.如果是快速中断:不管是否是同类型,都会被忽略
4.基于以上分析,为了避免中断丢失,我们要尽可能缩短中断处理的时间,从而引出了中断分层的概念。
中断分层
1.将中断分为上下两部分,上部分是必须放在中断处理函数的,对硬件相关的操作。下部分是对中断的判断以及检测后续的清理工作,交给内核处理。
2.中断分层有三种方式,分别为tasklet,软中断以及工作队列的方式。我们最常用的是工作队列的方式。
分层的具体过程
1.下半部分程序按照一定的格式形成内核能够识别的工作
2.将这个工作加入到CPU核上的工作队列(链表),以为内每一个CPU核都会创建一个工作队列
3.内核为每一个工作队列创建一个内核线程
4.在CPU空闲的时候调用该线程,从而执行相应的中断程序下部分。
5.执行完毕之后立即从队列中将该工作删除
1.执行某项工作实质上就是执行某一个函数,至于具体到哪一个函数就是看工作项是如何定义function成员的
2.工作队列的使用
1 (1)用workqueue_struct描述一个工作队列 2 struct workqueue_struct { 3 unsigned int flags; /* I: WQ_* flags */ 4 union { 5 struct cpu_workqueue_struct __percpu *pcpu; 6 struct cpu_workqueue_struct *single; 7 unsigned long v; 8 } cpu_wq; /* I: cwq‘s */ 9 struct list_head list; /* W: list of all workqueues */ 10 11 struct mutex flush_mutex; /* protects wq flushing */ 12 int work_color; /* F: current work color */ 13 int flush_color; /* F: current flush color */ 14 atomic_t nr_cwqs_to_flush; /* flush in progress */ 15 struct wq_flusher *first_flusher; /* F: first flusher */ 16 struct list_head flusher_queue; /* F: flush waiters */ 17 struct list_head flusher_overflow; /* F: flush overflow list */ 18 19 mayday_mask_t mayday_mask; /* cpus requesting rescue */ 20 struct worker *rescuer; /* I: rescue worker */ 21 22 int saved_max_active; /* W: saved cwq max_active */ 23 const char *name; /* I: workqueue name */ 24 #ifdef CONFIG_LOCKDEP 25 struct lockdep_map lockdep_map; 26 #endif 27 }; 28 29 (2)用work_struct描述一个工作项,相当于节点(队列成员) 30 struct work_struct { 31 atomic_long_t data; 32 struct list_head entry; 33 work_func_t func; 34 #ifdef CONFIG_LOCKDEP 35 struct lockdep_map lockdep_map; 36 #endif 37 };
(3)最关键的就是func成员
typedef void (*work_func_t)(struct work_struct *work);
他是下半部分实现的关键。
(4)工作队列实现中断分层三部曲: 创建工作队列(一般使用默认队列)---》创建工作---》挂载工作
(5)要想用中断分层必须加上MODULE_LICENSE(“GPL”);宏定义
(6)并非一挂载就立即执行工作,而是由内核线程自动判断何时执行工作。
实际使用中,不一定要用户自己手动创建工作队列,Linux内核已经自动创建了一个默认的一个工作队列keventd_wq,用户只需要创建一个工作以及提交给默认的工作队列(schedule_work(my_func))。通常在中断处理函数的结尾提交工作。
模板一(自己创建工作队列):
1 #include <linux/init.h> 2 #include <linux/module.h> 3 4 struct workqueue_struct *my_wq; 5 struct work_struct *work1; 6 struct work_struct *work2; 7 8 MODULE_LICENSE("GPL"); 9 10 void work1_func(struct work_struct *work) 11 { 12 printk("this is work1->\n"); 13 } 14 15 void work2_func(struct work_struct *work) 16 { 17 printk("this is work2->\n"); 18 } 19 20 int init_que(void) 21 { 22 //1. 创建工作队列 23 my_wq = create_workqueue("my_que"); // 24 25 //2. 创建工作 26 work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); 27 INIT_WORK(work1, work1_func); 28 29 //3. 挂载(提交)工作 30 queue_work(my_wq,work1); 31 32 33 //2. 创建工作 34 work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); 35 INIT_WORK(work2, work2_func); 36 37 //3. 挂载(提交)工作 38 queue_work(my_wq,work2); 39 40 return 0; 41 } 42 43 void clean_que() 44 { 45 46 } 47 48 49 module_init(init_que); 50 module_exit(clean_que);
模板二(使用默认工作队列):
1 #include <linux/init.h> 2 #include <linux/module.h> 3 4 struct workqueue_struct *my_wq; 5 struct work_struct *work1; 6 struct work_struct *work2; 7 8 MODULE_LICENSE("GPL"); 9 10 void work1_func(struct work_struct *work) 11 { 12 printk("this is work1->\n"); 13 } 14 15 void work2_func(struct work_struct *work) 16 { 17 printk("this is work2->\n"); 18 } 19 20 int init_que(void) 21 { 22 //2. 创建工作 23 work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); 24 INIT_WORK(work1, work1_func); 25 26 //3. 挂载(提交)工作 27 schedule_work(work1); 28 29 30 //2. 创建工作 31 work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); 32 INIT_WORK(work2, work2_func); 33 34 //3. 挂载(提交)工作 35 schedule_work(work2); 36 37 return 0; 38 } 39 40 void clean_que() 41 { 42 43 } 44 45 46 module_init(init_que); 47 module_exit(clean_que);
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。