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

一、tasklet_init(...)

        该函数的主要功能用于初始化tasklet_struct结构体。具体Linux内核源码设计如下:

        tasklet 为软中断,考虑到优先级问题,分别占用向量表(softirq_vec)中的 HI_SOFTIRQ 和 TASK_SOFTIRQ 两类软中断。驱动模块可以中断处理上半部分触发 TASKLET_SOFTIRQ。

tasklet 机制特性:

  • 跟普通软中断不一样,同一段 tasklet 代码在某个时刻只能在一个 CPU 上面执行,不销售一般 软中断服务函数(在同一时刻可以被多个 CPU 并发执行)。
  • 不同的 tasklet 代码同一时刻可以在多个 CPU 上并发执行。

        创建 tasklet 对象方式:静态创建和动态创建 (tasklet_init (…))。不管动态还是静态,都需要传递一个函数地址,此函数就是每个 tasklet 自己需要实现的处理函数 func 来改变一个 tasklet 对象状态。 

【代码案例】

taskletinit.c

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

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

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

    printk("打印输出tasklet对应的state成员:%ld\n",(&tl)->state);

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

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

    printk("打印输出调用tasklet_init()函数之前data的值:%ld\n",tl.data);
    if(tl.func==NULL)
        printk("tasklet没有初始化.\n");

    // 初始化tasklet_struct变量,相当我们要申请一个软中断
    tasklet_init(&tl,irqtasklet_actionfunc,data);
	
    if(tl.func==NULL)
        printk("taslet没有初始化.\n");
    else{
        printk("tasklet初始化成功.\n");
	printk("打印输出调用tasklet_init()函数after member data的值:%ld\n",tl.data);
    }

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

    return 0;
}

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

MODULE_LICENSE("GPL");

module_init(taskletinit_initfunc);
module_exit(taskletinit_exitfunc);

Makefile

#!/bin/bash

ccflags_y += -O2

ifneq ($(KERNELRELEASE),)
obj-m := taskletinit.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_schedule(...)

        该函数主要功能用于将参数t代表的软中断添加到向量tasklet_vec的尾部,并且触发一个软中断。具体Linux内核源码设计如下:       

        tasklet_vec 是一个 存储 tasklet 的数据结构,本质是一个 per-CPU 的 tasklet_head 数组:

  • 组织管理 tasklet:每个 CPU 对应一个 tasklet_head,维护该 CPU 上待执行的 tasklet 链表。驱动通过 __tasklet_schedule 把 tasklet 加入 tasklet_vec 中,内核后续会遍历该结构执行 tasklet 处理函数。
  • 配合软中断调度:作为软中断机制的一部分,tasklet_vec 存储的 tasklet 会在软中断触发时被统一处理,实现高效的中断下半部(耗时操作)异步执行,避免阻塞硬中断。

        通过此 tasklet_schedule () 函数修改中断状态值,设置 state 字段的值为 1,证明此中断被调用,将它加入中断等待队列当中。然后调用函数 __tasklet_schedule 将中断加入 tasklet_vec 中断向量链表的尾部,等待获取 CPU 资源并被调度处理。

【代码案例】

taskletschedule.c

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

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

// 自定义软中断处理函数
static void irqtasklet_actionfunc(unsigned long data){
    printk("调用自定义中断处理函数:irqtasklet_actionfunc(...)函数.\n");
    printk("data: %ld\n",data);
    printk("打印输出自定义中断处理函数tasklet的state的值:%ld\n",(&tl)->state); // 显示中断状态
    printk("退出自定义中断处理函数:irqtasklet_actionfunc(...)函数.\n");
}

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

    // 初始化tasklet
    tasklet_init(&tl,irqtasklet_actionfunc,data);
    printk("打印输出调用tasklet_init(...)函数之后的tasklet成员state的值为:%ld\n",(&tl)->state);// 显示中断状态

    // 将中断变量存放到软中断执行队列当中
    tasklet_schedule(&tl);

    printk("打印输出调用tasklet_schedule(...)函数之后的state成员的值为:%ld\n",(&tl)->state); // 显示中断状态

    printk("退出内核模块初始化函数:tasklet_schedule_initfunc(...)函数.\n");

    return 0;
}

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

MODULE_LICENSE("GPL");

module_init(tasklet_schedule_initfunc);
module_exit(tasklet_schedule_exitfunc);

Makefile

#!/bin/bash

ccflags_y += -O2

ifneq ($(KERNELRELEASE),)
obj-m := taskletschedule.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、付费专栏及课程。

余额充值