您的位置:首页 > 运维架构 > Linux

linux中断分层技术

2015-03-25 00:04 169 查看
为什么要中断分层?

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

中断分层

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

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

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

(1)用workqueue_struct描述一个工作队列
struct workqueue_struct {
unsigned int          flags;          /* I: WQ_* flags */
union {
struct cpu_workqueue_struct __percpu     *pcpu;
struct cpu_workqueue_struct          *single;
unsigned long                    v;
} cpu_wq;                    /* I: cwq's */
struct list_head     list;          /* W: list of all workqueues */

struct mutex          flush_mutex;     /* protects wq flushing */
int               work_color;     /* F: current work color */
int               flush_color;     /* F: current flush color */
atomic_t          nr_cwqs_to_flush; /* flush in progress */
struct wq_flusher     *first_flusher;     /* F: first flusher */
struct list_head     flusher_queue;     /* F: flush waiters */
struct list_head     flusher_overflow; /* F: flush overflow list */

mayday_mask_t          mayday_mask;     /* cpus requesting rescue */
struct worker          *rescuer;     /* I: rescue worker */

int               saved_max_active; /* W: saved cwq max_active */
const char          *name;          /* I: workqueue name */
#ifdef CONFIG_LOCKDEP
struct lockdep_map     lockdep_map;
#endif
};

(2)用work_struct描述一个工作项,相当于节点(队列成员)
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};


(3)最关键的就是func成员
typedef void (*work_func_t)(struct work_struct *work);
他是下半部分实现的关键。

(4)工作队列实现中断分层三部曲: 创建工作队列(一般使用默认队列)---》创建工作---》挂载工作

(5)要想用中断分层必须加上MODULE_LICENSE(“GPL”);宏定义

(6)并非一挂载就立即执行工作,而是由内核线程自动判断何时执行工作。

实际使用中,不一定要用户自己手动创建工作队列,Linux内核已经自动创建了一个默认的一个工作队列keventd_wq,用户只需要创建一个工作以及提交给默认的工作队列(schedule_work(my_func))。通常在中断处理函数的结尾提交工作。

模板一(自己创建工作队列):

#include <linux/init.h>
#include <linux/module.h>

struct workqueue_struct *my_wq;
struct work_struct *work1;
struct work_struct *work2;

MODULE_LICENSE("GPL");

void work1_func(struct work_struct *work)
{
printk("this is work1->\n");
}

void work2_func(struct work_struct *work)
{
printk("this is work2->\n");
}

int init_que(void)
{
//1. 创建工作队列
my_wq = create_workqueue("my_que");  //

//2. 创建工作
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1, work1_func);

//3. 挂载(提交)工作
queue_work(my_wq,work1);

//2. 创建工作
work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work2, work2_func);

//3. 挂载(提交)工作
queue_work(my_wq,work2);

return 0;
}

void clean_que()
{

}

module_init(init_que);
module_exit(clean_que);


模板二(使用默认工作队列):

#include <linux/init.h>
#include <linux/module.h>

struct workqueue_struct *my_wq;
struct work_struct *work1;
struct work_struct *work2;

MODULE_LICENSE("GPL");

void work1_func(struct work_struct *work)
{
printk("this is work1->\n");
}

void work2_func(struct work_struct *work)
{
printk("this is work2->\n");
}

int init_que(void)
{
//2. 创建工作
work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work1, work1_func);

//3. 挂载(提交)工作
schedule_work(work1);

//2. 创建工作
work2 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
INIT_WORK(work2, work2_func);

//3. 挂载(提交)工作
schedule_work(work2);

return 0;
}

void clean_que()
{

}

module_init(init_que);
module_exit(clean_que);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: