中断管理常用API详解(二)

一、__tasklet_hi_schedule(...)

        该函数的主要功能是将软中断具有比较高的优先级的任务优先调度处理。具体Linux内核源码设计如下:

        参数t:表示软中断的描述符添加到tasklet_hi_vec的尾部,获取CPU资源,被调度执行。 

调度优先级

  • __tasklet_schedule:调度的是普通优先级的 tasklet 。普通优先级的 tasklet 会在高优先级 tasklet 处理完之后,才会被内核调度执行 。当系统产生软中断时,普通 tasklet 不是最先被处理的对象 。
  • __tasklet_hi_schedule:用于调度高优先级的 tasklet 。在软中断处理过程中,高优先级的 tasklet 会优先于普通优先级的 tasklet 以及其他类型软中断(非高优先级软中断任务 )被处理。比如对于一些对响应时间要求苛刻的场景,像音频数据填充等低延迟需求的任务,就适合用 __tasklet_hi_schedule 来调度,以保证其能尽快执行。

所操作的队列

  • __tasklet_schedule:将 tasklet_struct 结构体(代表一个 tasklet 任务 )添加到 tasklet_vec 队列中。tasklet_vec 是每个 CPU 都有的一个用于存储普通优先级 tasklet 的队列 。
  • __tasklet_hi_schedule:把 tasklet_struct 结构体添加到 tasklet_hi_vec 队列 。tasklet_hi_vec 同样是每个 CPU 对应的队列,专门用来存放高优先级的 tasklet 。

触发的软中断类型

  • __tasklet_schedule:触发的是 TASKLET_SOFTIRQ 类型的软中断 。内核在处理软中断时,会根据软中断类型找到对应的处理逻辑,对于 TASKLET_SOFTIRQ 软中断,后续会执行 tasklet_vec 队列中注册的普通 tasklet 处理函数 。
  • __tasklet_hi_schedule:触发的是 HI_SOFTIRQ 类型的软中断 。当内核处理 HI_SOFTIRQ 软中断时,会去执行 tasklet_hi_vec 队列里的高优先级 tasklet 处理函数 。

 

【代码案例】

tasklethischedule.c

#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>

static struct tasklet_struct tl1, tl2;
static unsigned long data = 0;

static void irqtasklet_actionfunc1(unsigned long data) {
    printk("调用自定义中断处理函数:irqtasklet_actionfunc1(...)函数.\n");
    printk("data1 : %ld\n", data);
    printk("打印输出irqtasklet_actionfunc1(...)函数里面的tasklet成员state的值为:%ld\n", (&tl1)->state);
    printk("退出自定义中断处理函数:irqtasklet_actionfunc1(...)函数.\n");
}

static void irqtasklet_actionfunc2(unsigned long data) {
    printk("调用自定义中断处理函数:irqtasklet_actionfunc2(...)函数.\n");
    printk("data2 : %ld\n", data);
    printk("打印输出irqtasklet_actionfunc2(...)函数里面的tasklet成员state的值为:%ld\n", (&tl2)->state);
    printk("退出自定义中断处理函数:irqtasklet_actionfunc2(...)函数.\n");
}

static int __init tasklethischedule_initfunc(void) {
    printk("调用内核初始化函数:tasklethischedule_initfunc(...)函数.\n");

    tasklet_init(&tl1, irqtasklet_actionfunc1, data);
    tasklet_init(&tl2, irqtasklet_actionfunc2, data);

    printk("打印输出内核模块初始化函数:tasklet的state成员值为:%ld\n", (&tl1)->state);
    printk("打印输出内核模块初始化函数:tasklet的state成员值为:%ld\n", (&tl2)->state);

    tasklet_schedule(&tl1);
    if(!test_and_set_bit(TASKLET_STATE_SCHED,&tl2.state)) // 测试并且设置中断状态
        __tasklet_hi_schedule(&tl2); // 将中断加入高优先级队列
    
    mdelay(10); // 等待执行

    printk("退出内核初始化函数:tasklethischedule_initfunc(...)函数.\n");
    return 0;
}

static void __exit tasklethischedule_exitfunc(void) {
    tasklet_kill(&tl2); // 自动等待高优先级 tasklet 执行完毕
    tasklet_kill(&tl1); // 自动等待普通优先级 tasklet 执行完毕
    printk("内核正常退出:__tasklet_hi_schedule(...)函数.\n");
}

MODULE_LICENSE("GPL");
module_init(tasklethischedule_initfunc);
module_exit(tasklethischedule_exitfunc);

Makefile

#!/bin/bash

ccflags_y += -O2

ifneq ($(KERNELRELEASE),)
obj-m := tasklethischedule.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
endif

clean:
	rm -rf *.o *.ko *.mod.c

depend .depend dep:
	$(CC)  -M *.c > .depend 

编译插入卸载

 

二、tasklet_kill(...)

        该函数主要功能是阻塞当前线程,等待中断处理执行完毕。中断函数处理完毕state清0.具体内核源码设计如下:

tasklet特性:

  • 可以指定优先级;
  • 反复启用、禁用,在多次禁用之后必须先启用才能作用;
  • tasklet 可以嵌套,也就是它可以注册自己。

 【代码案例】

taskletkill.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>

static unsigned long data=0;
static struct tasklet_struct tl;

static void irqtasklet_actionfunc(unsigned long data){
    printk("调用自定义中断函数:irqtasklet_actionfunc(...)函数.\n");

    printk("data : %ld\n",data);

    printk("输出irqtasklet_actionfunc(...)函数tasklet的state成员值为:%ld\n",(&tl)->state);

    printk("退出自定义中断函数:irqtasklet_actionfunc(...)函数.\n");
}

static int __init taskletkill_initfunc(void){
    printk("调用内核模块函数:taskletkill_initfunc(...)函数.\n");

    tasklet_init(&tl,irqtasklet_actionfunc,data);
    printk("输出taskletkill_initfunc(...)函数tasklet的state成员值为:%ld\n",(&tl)->state);

    tasklet_schedule(&tl); // 将中断变量加入到软中断执行队列
    printk("输出taskletkill_initfunc(...)函数tasklet调用tasklet_schedule函数之后的state成员值为:%ld\n",(&tl)->state);

    tasklet_kill(&tl);
    printk("打印输出当前中断状态state成员值为:%ld\n",(&tl)->state);

    printk("退出内核模块函数:taskletkill_initfunc(...)函数.\n");

    return 0;
}

static void __exit taskletkill_exitfunc(void){
    printk("正常退出内核:tasklet_kill(...)函数.\n");
}

MODULE_LICENSE("GPL");
module_init(taskletkill_initfunc);
module_exit(taskletkill_exitfunc);

Makefile

#!/bin/bash

ccflags_y += -O2

ifneq ($(KERNELRELEASE),)
obj-m := taskletkill.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 
endif

clean:
	rm -rf *.o *.ko *.mod.c

depend .depend dep:
	$(CC)  -M *.c > .depend 

编译插入卸载

 

https://github.com/0voice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值