全部博文(18)
分类: LINUX
2009-04-08 14:33:15
7.1 下半部
任务:执行与中断处理密切相关而中断处理程序本身不执行的工作。
=> 减少中断处理程序的运行时间;
下半部通常在中断处理程序返回时就会执行,且允许所有中断。
三种下半部实现机制:
软中断、tasklet、工作队列
7.2 软中断
7.2.1 软中断的实现
|
软中断处理程序:void softirq_handler(struct softirq_action *)
执行软中断(do_softirq()):
软中断不会抢占另一个软中断,一个注册的软中断在标记后才会执行(触发软中断);
其他软中断,甚至是相同类型软中断,可以在其他处理器上同时执行;
中断处理程序返回前 => 标记它的软中断
=> 软中断被检查和执行(条件:从一个硬件中断代码返回;
在ksoftirqd内核线程中;
在显式检查和执行待处理的软中断的代码中)
|
7.2.2 使用软中断
(1) 分配索引
Tasklet |
Priority |
Softirq Description |
HI_SOFTIRQ |
0 |
High-priority tasklets 优先级高的tasklet |
TIMER_SOFTIRQ |
1 |
Timer bottom half 定时器的下半部 |
NET_TX_SOFTIRQ |
2 |
Send network packets 发送网络数据包 |
NET_RX_SOFTIRQ |
3 |
Receive network packets 接收网络数据包 |
SCSI_SOFTIRQ |
4 |
SCSI bottom half SCSI的下半部 |
TASKLET_SOFTIRQ |
5 |
Tasklets |
说明:
定义在
建立一个新的软中断必须在此枚举类型中加入新项;
HI_SOFTIRQ为第一项,TASKLET_SOFTIRQ为最后一项,新项可插在网络项之后,TASKLET_SOFTIRQ之前;
(2) 注册软中断处理程序
open_softirq()
参数:软中断索引号、处理函数、data域存放的数值
(3) 触发软中断
raise_softirq()或raise_softirq_irqoff()
参数:软中断索引号
总结:
中断处理程序执行硬件相关的操作,然后触发相应的软中断,并退出;
内核执行完中断处理程序,调用do_softirq()函数,软中断执行中断处理程序的剩余任务(下半部);
软中断很少使用,用于执行频率和连续性都很高的情况;
通常用tasklet。
7.3 tasklet
tasklet结构体:
|
调度tasklet:tasklet_schedule()和tasklet_hi_schedule()(接收一个指向tasklet_struct结构的指针作为参数)
已调度的tasklet存放在tasklet_vec和tasklet_hi_vec中,它们是由tasklet_struct构成的链表。
运用HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断。
使用tasklet:(1) 声明tasklet——静态:DECLARE_TASKLET(name, func, data)或DECLARE_TASKLET_DISABLED(name, func, data);
动态:tasklet_init(t, tasklet_handler, dev)
(2) 编写tasklet处理程序——void tasklet_handler(unsigned long data)
(3) 调度tasklet——tasklet_schedule(&my_tasklet)
ksoftirqd:用于辅助处理软中断的内核线程;只要有待处理的软中断,ksoftirqd就会调用do_softirq去处理它们
7.4 工作队列
推后执行的任务可以睡眠;
工作队列允许重新调度;
可以中内核线程替换。
工作队列的实现:
内核线程-工作者线程(worker thread)
默认的工作者线程叫events/n,n是处理器的编号;
1 表示线程的数据结构-workqueue_struct
|
2 表示工作的数据结构-work_struct
|
这些结构体连接成链表;
工作者线程用普通的内核线程实现的,执行worker_thread()函数;
3 run_workqueue()
使用工作队列:
(1) 创建推后的工作
静态:DECLARE_WORK(name, void (*func)(void *), void *data);
动态:INIT_WORK(struct work_struct *work, void(* func)(void *), void *data);
(2) 工作队列处理函数
void work_handler(void *data)
(3) 对工作进行调度
schedule_work(&work);
schedule_delayed_work(&work, delay);
(4) 刷新操作
void flush_scheduled_work(void);
(5) 创建新的工作队列
默认的队列不能满足需要的情况下
srruct workqueue_struct *create_workqueue(const char *name)
调度自己创建的工作队列:
int queue_work(struct workqueue_struct *wq, struct work_struct *work)
int queue_delayed_work(struct workqueue_struct *wq,
struct work_struct *work,
unsigned long delay)
7.5 下半部机制的选择
Bottom Half |
Context |
Inherent Serialization |
Softirq |
Interrupt |
None |
Tasklet |
Interrupt |
Against the same tasklet |
Work queues |
Process |
None (scheduled as process context) |