中断下半部之 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的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动: 中断下半部之tasklet&workqueue

Linux内核中的下半部机制之tasklet

Linux内核中的下半部机制之tasklet

中断下半部之 work queue

中断下半部之 work queue

《深入理解Linux内核》软中断/tasklet/工作队列