linux中断分层技术

为什么要中断分层?

中断嵌套
1.当一个中断处理的时候,发生另一个中断。
2.如果是慢速中断:
(1)同类型的中断会被忽略
(2)不同类型的会被响应
3.如果是快速中断:不管是否是同类型,都会被忽略
4.基于以上分析,为了避免中断丢失,我们要尽可能缩短中断处理的时间,从而引出了中断分层的概念。

 

中断分层

1.将中断分为上下两部分,上部分是必须放在中断处理函数的,对硬件相关的操作。下部分是对中断的判断以及检测后续的清理工作,交给内核处理。
2.中断分层有三种方式,分别为tasklet,软中断以及工作队列的方式。我们最常用的是工作队列的方式

分层的具体过程
1.下半部分程序按照一定的格式形成内核能够识别的工作
2.将这个工作加入到CPU核上的工作队列(链表),以为内每一个CPU核都会创建一个工作队列
3.内核为每一个工作队列创建一个内核线程
4.在CPU空闲的时候调用该线程,从而执行相应的中断程序下部分。
5.执行完毕之后立即从队列中将该工作删除


1.执行某项工作实质上就是执行某一个函数,至于具体到哪一个函数就是看工作项是如何定义function成员的
2.工作队列的使用

 11)用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 
292)用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);

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。