- 论坛徽章:
- 0
|
7.1 下半部
任务:执行与中断处理密切相关而中断处理程序本身不执行的工作。
=> 减少中断处理程序的运行时间;
下半部通常在中断处理程序返回时就会执行,且允许所有中断。
三种下半部实现机制:
软中断、tasklet、工作队列
7.2 软中断
7.2.1 软中断的实现
/*
* structure representing a single softirq entry 软中断结构
*/
struct softirq_action {
void (*action)(struct softirq_action *); /* function to run */
void *data; /* data to pass to function */
};
static struct softirq_action softirq_vec[32];最多有32个软中断
软中断处理程序:void softirq_handler(struct softirq_action *)
执行软中断(do_softirq()):
软中断不会抢占另一个软中断,一个注册的软中断在标记后才会执行(触发软中断);
其他软中断,甚至是相同类型软中断,可以在其他处理器上同时执行;
中断处理程序返回前 => 标记它的软中断
=> 软中断被检查和执行(条件:从一个硬件中断代码返回;
在ksoftirqd内核线程中;
在显式检查和执行待处理的软中断的代码中)
u32 pending = softirq_pending(cpu);//softirq_pending()返回的是待处理软中断的32位位图
if (pending) {
struct softirq_action *h = softirq_vec;
softirq_pending(cpu) = 0;
do {
if (pending & 1)
h->action(h);
h++;
pending >>= 1;
} while (pending); //这个循环最多执行32次
}
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结构体:
struct tasklet_struct {
struct tasklet_struct *next; /* next tasklet in the list */
unsigned long state; /* state of the tasklet :
0;TASKLET_STATE_SCHED(tasklet已被调度,准备运行);TASKLET_STATE_RUN(正在运行)*/
atomic_t count; /* reference counter为0时tasklet才被激活 */
void (*func)(unsigned long); /* tasklet handler function */
unsigned long data; /* argument to the tasklet function */
};
调度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
struct workqueue_struct {
struct cpu_workqueue_struct cpu_wq[NR_CPUS];
const char *name;
struct list_head list;
};
struct cpu_workqueue_struct {
spinlock_t lock; /* lock protecting this structure */
long remove_sequence; /* least-recently added (next to run) */
long insert_sequence; /* next to add */
struct list_head worklist; /* list of work */
wait_queue_head_t more_work;
wait_queue_head_t work_done;
struct workqueue_struct *wq; /* associated workqueue_struct */
task_t *thread; /* associated thread */
int run_depth; /* run_workqueue() recursion depth */
};
2 表示工作的数据结构-work_struct
struct work_struct {
unsigned long pending; /* is this work pending? */
struct list_head entry; /* link list of all work */
void (*func)(void *); /* handler function */
void *data; /* argument to handler */
void *wq_data; /* used internally */
struct timer_list timer; /* timer used by delayed work queues */
};
这些结构体连接成链表;
工作者线程用普通的内核线程实现的,执行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)
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/85048/showart_1893908.html |
|