Linux内核API __tasklet_hi_schedule

__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所示的结果。

Linux内核API __tasklet_hi_schedule

如果将函数__tasklet_hi_schedule( )及上面的if( )条件判断都注释掉,替换成函数tasklet_schedule( ),重新编译模块,插入模块,输入命令dmesg -c出现如图B所示的结果。

Linux内核API __tasklet_hi_schedule

结果分析:

由图A可以看出当中断处理函数被调度执行时,当前中断的状态值是2,可以判断当前state字段的bit[1]是1,而bit[1]=1表示当前中断正在执行,二者相吻合。图A和图B的唯一区别是两个中断处理函数被调度执行的顺序不同,在图A中经过函数__tasklet_hi_schedule( )处理的软中断,其先被调度执行,此不是偶然,也非必然,但是大部分情况都是图A出现的情况,因为函数__tasklet_hi_schedule( )注册的软中断具有较高的优先级,能先被调度处理。

赞(1)
未经允许不得转载:极客笔记 » Linux内核API __tasklet_hi_schedule
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址