__tasklet_hi_schedule函数功能描述:函数__tasklet_hi_schedule( )的主要作用是将参数t代表的软中断的描述符添加到向量tasklet_hi_vec的尾部,等待获得CPU资源,被调度执行。tasklet_hi_vec代表高优先级的软中断描述符链表。通过此函数添加的软中断具有较高的优先级,会先被调度处理。
__tasklet_hi_schedule文件包含
#include<linux/interrupt.h>
__tasklet_hi_schedule函数定义
在内核源码中的位置:linux-3.19.3/kernel/softirq.c
函数定义格式:
void __tasklet_hi_schedule(struct tasklet_struct *t)
__tasklet_hi_schedule输入参数说明
函数输入参数是struct tasklet_struct结构体类型的指针,保存软中断的描述符信息,其定义见文件linux-3.19.3/include/linux/interrupt.h,如下:
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
其中:
- 字段
next
指向链表的下一个元素。 - 字段
state
定义了当前软中断的状态,是一个32位的无符号长整数,内核系统中只使用了bit[1]和bit[0]两个状态位。其中,bit[1]=1表示当前tasklet正在执行,它仅对SMP系统有意义,其作用就是为了防止多个CPU同时执行一个tasklet的情形出现;bit[0]=1表示当前tasklet已经被调度,等待获得CPU资源执行。对这两个状态位的宏定义如下所示(interrupt.h):
enum
{
TASKLET_STATE_SCHED, /* 软中断被调度,但未执行*/
TASKLET_STATE_RUN /*软中断正在执行 */
};
- 字段
count
是一个原子计数器,代表当前tasklet的引用计数值。只有当count等于0时,tasklet对应的中断处理函数才能被执行,也即此时tasklet是被使能的;如果count非零,则这个tasklet是被禁止的。 - 字段
func
是一个函数指针,代表中断的处理函数。 - 字段
data
代表中断处理函数执行时的参数,即字段func代表函数执行时的参数,是一个32位的无符号整数,其具体含义可由func字段指向的函数自行解释,比如将其解释成一个指向某个用户自定义数据结构的地址值等。
__tasklet_hi_schedule返回参数说明
此函数的返回值是void类型的变量,即函数不返回任何值。
__tasklet_hi_schedule实例解析
编写测试文件:__tasklet_hi_schedule.c
头文件引用及全局变量定义:
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE(“GPL”);
static unsigned long data=0;
static struct tasklet_struct tasklet, tasklet1;
中断处理函数定义:
// 自定义软中断处理函数,在此只是显示的作用
static void irq_tasklet_action(unsigned long data)
{
/*显示当前软中断的状态*/
printk("in irq_tasklet_action the state of the tasklet is :%ld\n", (&tasklet)->state);
printk("tasklet running. by author\n");
return;
}
// 自定义软中断处理函数,在此只是显示的作用
static void irq_tasklet_action1(unsigned long data)
{
/*显示当前软中断的状态*/
printk("in irq_tasklet_action1 the state of the tasklet1 is :%ld\n", (&tasklet1)->state);
printk("tasklet1 running. by author\n");
return;
}
模块初始化函数定义:
static int __init __tasklet_hi_schedule_init(void)
{
printk("into __tasklet_hi_schedule\n");
// 申请两个软中断
tasklet_init(&tasklet, irq_tasklet_action, data);
tasklet_init(&tasklet1, irq_tasklet_action1, data);
printk("The state of the tasklet is :%ld\n", (&tasklet)->state);
// 显示当前中断的状态
printk("The state of the tasklet1 is :%ld\n", (&tasklet1)->state);
tasklet_schedule(&tasklet); //把中断送入普通中断队列
if(! test_and_set_bit(TASKLET_STATE_SCHED, &tasklet1.state))//测试并设置中断的状态
__tasklet_hi_schedule(&tasklet1); // 把中断送入高优先级队列
// tasklet_schedule(&tasklet1);
tasklet_kill(&tasklet); //等待中断处理函数执行完毕,恢复调度之前的状态
tasklet_kill(&tasklet1);
printk("out __tasklet_hi_schedule\n");
return 0;
}
模块退出函数定义:
static void __exit __tasklet_hi_schedule_exit(void)
{
printk("Goodbye __tasklet_hi_schedule\n");
return;
}
模块加载、退出函数调用:
module_init(__tasklet_hi_schedule_init);
module_exit(__tasklet_hi_schedule_exit);
实例结果及分析:
执行命令insmod __tasklet_hi_schedule.ko加载模块,然后输入命令dmesg -c查看内核输出信息,出现如图A
所示的结果。
如果将函数__tasklet_hi_schedule( )及上面的if( )条件判断都注释掉,替换成函数tasklet_schedule( ),重新编译模块,插入模块,输入命令dmesg -c出现如图B
所示的结果。
结果分析:
由图A
可以看出当中断处理函数被调度执行时,当前中断的状态值是2,可以判断当前state字段的bit[1]是1,而bit[1]=1表示当前中断正在执行,二者相吻合。图A
和图B
的唯一区别是两个中断处理函数被调度执行的顺序不同,在图A
中经过函数__tasklet_hi_schedule( )处理的软中断,其先被调度执行,此不是偶然,也非必然,但是大部分情况都是图A
出现的情况,因为函数__tasklet_hi_schedule( )注册的软中断具有较高的优先级,能先被调度处理。