level 9
浩淼56
楼主
中断下半部
断处理流程都会分为两部分:上半部分(tophalf)和下半部分(bottomhalf)。
1.中断可以随时的打断处理机对其他程序的执行,如果被打断的代码对系统很重要,那么此时中断处理程序的执行时间应该是越短越好。
2.通过上文我们知道,中断处理程序正在执行时,会屏蔽同条中断线上的中断请求;而更严重的是,如果设置了IRQF_DISABLED,那么该中断服务程序执行是会屏蔽所有其他的中断请求。那么此时应该让中断处理程序执行的越快越好。
这样划分是有一定原因的,因为我们必须有一个快速、异步而且简单的处理程序专门来负责对硬件的中断请求做出快速响应,与此同时也要完成那些对时间要求很严格的操作。而那些对时间要求相对宽松,其他的剩余工作则会在稍候的任意时间执行,也就是在所谓的下半部分去执行。
下半部可以通过多种机制来完成:小任务(tasklet),工作队列,软中断。不管是那种机制,它们均为下半部提供了一种执行机制,比上半部灵活多了。至于何时执行,则由内核负责。
如果该任务对时间比较敏感,将其放在上半部中执行。
如果该任务和硬件相关,一般放在上半部中执行。
如果该任务要保证不被其他中断打断,放在上半部中执行(因为这是系统关中断)。
其他不太紧急的任务,一般考虑在下半部执行。
tasklet
tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的。正如在前文中你所知道的那样,一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用tasklet使得下半部分的工作得以完成。可以看到,下半部分被上半部分所调用,至于下半部分何时执行则属于内核的工作。
tasklet由tasklet_struct结构体来表示,每一个这样的结构体就表示一个tasklet。在<linux/interrupt.h>中可以看到如下的定义:
tasklet_struct
{ structtasklet_struct *next; 链表中的下一个tasklet
unsigned long state; 此刻tasklet的状态 TASKLET_STATE_SCHED(准备运行) TASKLET_STATE_RUN(正在运行)
atomic_t count; count成员是一个引用计数器,只有当其值为0时候,tasklet才会被激活;否则被禁止,不能被执行。
void (*func)(unsigned long); 指向tasklet处理函数
unsigned long data; 处理函数的唯一参数为data
};
在使用tasklet前,必须首先创建一个tasklet_struct类型的变量。通常有两种方法:静态创建和动态创建。如同上半部分的中断处理程序一样,这个函数需要我们自己来实现。
void tasklet_handler(unsigned long data) 然后在小任务的调度来执行.
在上半部中通过调用tasklet,使得对时间要求宽松的那部分中断程序推后执行。
工作队列
工作队列(work queue)可以实现一些tasklet不能实现的工作,比如工作队列机制可以睡眠。这种差异的本质原因是,在工作队列机制中,将推后的工作交给一个称之为工作者线程(worker thread)的内核线程去完成。因此,在该机制中,当内核在执行中断的剩余工作时就处在进程上下文(process context)中。也就是说由工作队列所执行的中断代码会表现出进程的一些特性,最典型的就是可以重新调度甚至睡眠。
进程上下文:一般的进程运行在用户态,如果这个进程进行了系统调用,那么此时用户空间中的程序就进入了内核空间,并且称内核代表该进程运行于内核空间中。由于用户空间和内核空间具有不同的地址映射,并且用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。这样就产生了进程上下文。
所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容。当内核需要切换到另一个进程时(上下文切换),它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态继续执行。上述所说的工作队列所要做的工作都交给工作者线程来处理,因此它可以表现出进程的一些特性,比如说可以睡眠等。
内核中通过下述结构体来表示一个具体的工作:
struct work_struct
{
unsigned long pending;//这个工作是否正在等待处理
struct list_head entry;//链接所有工作的链表,形成工作队列
void (*func)(void *);//处理函数
void *data;//传递给处理函数的参数
void *wq_data;//内部使用数据
struct timer_list timer;//延迟的工作队列所用到的定时器
};
而这些工作(结构体)链接成的链表就是所谓的工作队列。工作者线程会在被唤醒时执行链表上的所有工作,当一个工作被执行完毕后,相应的work_struct结构体也会被删除。当这个工作链表上没有工作时,工作线程就会休眠。
软中断
软中断 (softirq)是用软件方式模拟硬件中断的概念,实现宏观上的异步执行效果。softirq 是基本的下半部机制,需要互斥使用。只能使用一种软件中断,其优先级低于硬件中断的,但是高于普通的进程优先级. 软中断不会抢占另一个软中断,只有中断处理函数才能抢占一个软中断
每个注册的软中断占据数组的一项,因此,总共有NR_SOFTIRQS个注册的软中断。软中断的数目是在编译时静态决定的,不能动态更改。内核中软中断个数的限制是32个,但在当前内核中,只有9个。
一个注册的软中断必须被标记后,才能运行。这称之为触发,实质上就是将其标记为未决状态。通常,中断处理函数会触发一个软中断,然后返回。在合适的时间,软中断会执行。
软中断----“谁触发,谁执行”(Whomarks, who runs),也就是说,每个CPU都单独负责它所触发的软中断,互不干扰。
3 几种下半部机制的比较
Linux内核提供的几种下半部机制都用来推后执行你的工作,但是它们在使用上又有诸多差异,各自有不同的适用范围,使用时应该加以区分。
Linux 2.6内核提供的几种软中断机制都贯穿着“谁触发,谁执行”的思想,但是它们各自有不同的特点。softirq是整个软中断框架体系的核心,是最底层的一种机制,内核程序员很少直接使用它,大部分应用,我们只需要使用tasklet就行了。
2016年08月09日 11点08分
1
断处理流程都会分为两部分:上半部分(tophalf)和下半部分(bottomhalf)。
1.中断可以随时的打断处理机对其他程序的执行,如果被打断的代码对系统很重要,那么此时中断处理程序的执行时间应该是越短越好。
2.通过上文我们知道,中断处理程序正在执行时,会屏蔽同条中断线上的中断请求;而更严重的是,如果设置了IRQF_DISABLED,那么该中断服务程序执行是会屏蔽所有其他的中断请求。那么此时应该让中断处理程序执行的越快越好。
这样划分是有一定原因的,因为我们必须有一个快速、异步而且简单的处理程序专门来负责对硬件的中断请求做出快速响应,与此同时也要完成那些对时间要求很严格的操作。而那些对时间要求相对宽松,其他的剩余工作则会在稍候的任意时间执行,也就是在所谓的下半部分去执行。
下半部可以通过多种机制来完成:小任务(tasklet),工作队列,软中断。不管是那种机制,它们均为下半部提供了一种执行机制,比上半部灵活多了。至于何时执行,则由内核负责。
如果该任务对时间比较敏感,将其放在上半部中执行。
如果该任务和硬件相关,一般放在上半部中执行。
如果该任务要保证不被其他中断打断,放在上半部中执行(因为这是系统关中断)。
其他不太紧急的任务,一般考虑在下半部执行。
tasklet
tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的。正如在前文中你所知道的那样,一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用tasklet使得下半部分的工作得以完成。可以看到,下半部分被上半部分所调用,至于下半部分何时执行则属于内核的工作。
tasklet由tasklet_struct结构体来表示,每一个这样的结构体就表示一个tasklet。在<linux/interrupt.h>中可以看到如下的定义:
tasklet_struct
{ structtasklet_struct *next; 链表中的下一个tasklet
unsigned long state; 此刻tasklet的状态 TASKLET_STATE_SCHED(准备运行) TASKLET_STATE_RUN(正在运行)
atomic_t count; count成员是一个引用计数器,只有当其值为0时候,tasklet才会被激活;否则被禁止,不能被执行。
void (*func)(unsigned long); 指向tasklet处理函数
unsigned long data; 处理函数的唯一参数为data
};
在使用tasklet前,必须首先创建一个tasklet_struct类型的变量。通常有两种方法:静态创建和动态创建。如同上半部分的中断处理程序一样,这个函数需要我们自己来实现。
void tasklet_handler(unsigned long data) 然后在小任务的调度来执行.
在上半部中通过调用tasklet,使得对时间要求宽松的那部分中断程序推后执行。
工作队列
工作队列(work queue)可以实现一些tasklet不能实现的工作,比如工作队列机制可以睡眠。这种差异的本质原因是,在工作队列机制中,将推后的工作交给一个称之为工作者线程(worker thread)的内核线程去完成。因此,在该机制中,当内核在执行中断的剩余工作时就处在进程上下文(process context)中。也就是说由工作队列所执行的中断代码会表现出进程的一些特性,最典型的就是可以重新调度甚至睡眠。
进程上下文:一般的进程运行在用户态,如果这个进程进行了系统调用,那么此时用户空间中的程序就进入了内核空间,并且称内核代表该进程运行于内核空间中。由于用户空间和内核空间具有不同的地址映射,并且用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。这样就产生了进程上下文。
所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容。当内核需要切换到另一个进程时(上下文切换),它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态继续执行。上述所说的工作队列所要做的工作都交给工作者线程来处理,因此它可以表现出进程的一些特性,比如说可以睡眠等。
内核中通过下述结构体来表示一个具体的工作:
struct work_struct
{
unsigned long pending;//这个工作是否正在等待处理
struct list_head entry;//链接所有工作的链表,形成工作队列
void (*func)(void *);//处理函数
void *data;//传递给处理函数的参数
void *wq_data;//内部使用数据
struct timer_list timer;//延迟的工作队列所用到的定时器
};
而这些工作(结构体)链接成的链表就是所谓的工作队列。工作者线程会在被唤醒时执行链表上的所有工作,当一个工作被执行完毕后,相应的work_struct结构体也会被删除。当这个工作链表上没有工作时,工作线程就会休眠。
软中断
软中断 (softirq)是用软件方式模拟硬件中断的概念,实现宏观上的异步执行效果。softirq 是基本的下半部机制,需要互斥使用。只能使用一种软件中断,其优先级低于硬件中断的,但是高于普通的进程优先级. 软中断不会抢占另一个软中断,只有中断处理函数才能抢占一个软中断
每个注册的软中断占据数组的一项,因此,总共有NR_SOFTIRQS个注册的软中断。软中断的数目是在编译时静态决定的,不能动态更改。内核中软中断个数的限制是32个,但在当前内核中,只有9个。
一个注册的软中断必须被标记后,才能运行。这称之为触发,实质上就是将其标记为未决状态。通常,中断处理函数会触发一个软中断,然后返回。在合适的时间,软中断会执行。
软中断----“谁触发,谁执行”(Whomarks, who runs),也就是说,每个CPU都单独负责它所触发的软中断,互不干扰。
3 几种下半部机制的比较
Linux内核提供的几种下半部机制都用来推后执行你的工作,但是它们在使用上又有诸多差异,各自有不同的适用范围,使用时应该加以区分。
Linux 2.6内核提供的几种软中断机制都贯穿着“谁触发,谁执行”的思想,但是它们各自有不同的特点。softirq是整个软中断框架体系的核心,是最底层的一种机制,内核程序员很少直接使用它,大部分应用,我们只需要使用tasklet就行了。