中断下半部之 tasklet
Posted Li-Yongjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了中断下半部之 tasklet相关的知识,希望对你有一定的参考价值。
简介
tasklet 是利用软中断实现的一种下半部机制。
选择到底是使用软中断还是 tasklet 其实很简单:通常你应该用 tasklet。
引入软中断的主要原因是其可扩展性。如果不需要扩展到多个处理器,那么,就使用 tasklet 吧。tasklet 本质上也是软中断,只不过同一个处理程序的多个实例不能在多个处理器上同时运行。软中断只在那些执行频率很高和连续性要求很高的情况下才需要。
而 tasklet 却有更广泛的用途。大多数情况下用 tasklet 效果都不错,而且它们还非常容易使用。
tasklet 由两类软中断代表:HI_SOFTIRQ 和 TASKLET_SOFTIRQ。这两者之间唯一的区别在于前者优先级比后者高。
使用
① 声明你自己的 tasklet
静态创建
DECLARE_TASKLET(name, _callback)
DECLARE_TASKLET_DISABLED(name, _callback)
动态创建
tasklet_init()
② 编写你自己的 tasklet 程序
void tasklet_fn(unsigned long data)
注意,因为是靠软中断实现,所以 tasklet 不能睡眠。
tasklet 运行时允许响应中断,所以你必须做好预防工作(比如屏蔽中断然后获取一个锁)。
③ 调度你自己的 tasklet
tasklet 由以下两个函数进行调度。
tasklet_schedule()
tasklet_hi_schedule()
实例
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#define BUTTON_PIN 12 /* GPIO 12 */
int flag = 0;
struct tasklet_struct tsklt;
void tasklet_fn(unsigned long data)
printk("%s(), %s\\n", __func__, current->comm);
static irqreturn_t irq_handler(int irq, void *dev) // 上半部
printk("%s(): enter\\n", __FUNCTION__);
tasklet_hi_schedule(&tsklt);
printk("%s(): exit\\n", __FUNCTION__);
return IRQ_HANDLED;
static int led_init(void)
int err;
int irq;
printk("%s()\\n", __FUNCTION__);
tasklet_init(&tsklt, tasklet_fn, 0);
err = gpio_request_one(BUTTON_PIN, GPIOF_IN, "Button");
if (err)
return err;
irq = gpio_to_irq(BUTTON_PIN);
// enable_irq(irq); // why crash ?
err = request_irq(irq, irq_handler, IRQ_TYPE_EDGE_BOTH, "LED Test", NULL);
if (err < 0)
printk("request irq (%d) failed!\\n", irq);
return err;
printk("request irq (%d) success!\\n", irq);
flag = 1;
return 0;
static void led_exit(void)
printk("%s()\\n", __FUNCTION__);
if (flag)
free_irq(gpio_to_irq(BUTTON_PIN), NULL);
gpio_free(BUTTON_PIN);
return;
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("Dual BSD/GPL");
其它相关源码参考上篇文章。
测试
# tftp -gr irq_tasklet.ko 192.168.31.224
#
# insmod irq_tasklet.ko
[39721.126865] led_init()
[39721.130762] request irq (200) success!
#
# ./gpioout.out 1
[39724.639370] irq_handler(): enter
[39724.644089] irq_handler(): exit
[39724.648772] tasklet_fn(), swapper/0
[39725.639452] irq_handler(): enter
[39725.644161] irq_handler(): exit
[39725.648807] tasklet_fn(), swapper/0
#
# rmmod irq_tasklet.ko
[39732.248225] led_exit()
#
执行中断服务程序后,紧接着执行 tasklet_fn(),符合预期。
以上是关于中断下半部之 tasklet的主要内容,如果未能解决你的问题,请参考以下文章