linux tasklet 的分析与使用

2023-11-02

linux tasklet 的分析与使用


tasklet 是利用软中断实现的一种下半部机制,本质上是软中断的一种变种,运行在中断上下文中.
有关于软中断的分析,可以参考之前的文章,有详细的分析。

tasklet 源码分析

interrupt.h 文件下,tasklet_struct结构体见下面代码,代码中有注释说明;

enum
{
	TASKLET_STATE_SCHED,	/* Tasklet is scheduled for execution */
	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
};
struct tasklet_struct
{
	struct tasklet_struct *next; //多个tasklet 串成一个链表
	unsigned long state; // 表示调试状态,见上面的枚举 TASKLET_STATE_SCHED
	atomic_t count; // 0 表示tasklet 处理激活状态; 不为0表示tasklet 被禁止,不允许执行
	void (*func)(unsigned long); // 处理函数
	unsigned long data; //处理函数的数据
};

每个cpu维护两个tasklet 链表,在softirq.c中 tasklet_vec 和tasklet_hi_vec;
tasklet_vec 在软中断的优先级是6,见软中断文章中的枚举,tasklet_hi_vec的优先级是0
在softirq.c 中函数softirq_init 使用,而softirq_init 又被系统启动时调用。

/*
 * Tasklets
 */
struct tasklet_head {
	struct tasklet_struct *head;
	struct tasklet_struct **tail;
};

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

void __init softirq_init(void)
{
	int cpu;

	for_each_possible_cpu(cpu) {
		per_cpu(tasklet_vec, cpu).tail =
			&per_cpu(tasklet_vec, cpu).head;
		per_cpu(tasklet_hi_vec, cpu).tail =
			&per_cpu(tasklet_hi_vec, cpu).head;
	}

	open_softirq(TASKLET_SOFTIRQ, tasklet_action);
	open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

系统启动时调用

asmlinkage __visible void __init start_kernel(void)
{
	char *command_line;
	char *after_dashes;
	.......
	/* Trace events are available after this */
	trace_init();

	context_tracking_init();
	/* init some links before init_ISA_irqs() */
	early_irq_init();
	init_IRQ();
	tick_init();
	rcu_init_nohz();
	init_timers();
	hrtimers_init();
	softirq_init();   //软中断初始化
	timekeeping_init();
	time_init();
	......
}

同一个tasklet不会同时运行,所以不需要处理tasklet和它本身之间的锁定情况。但是两个tasklet之间共享数据都应该使用spin_lock()和spin_unlock()进行保护

tasklet_shedule 调度的分析

相关代码如下:

//interrupt.h
static inline void tasklet_schedule(struct tasklet_struct *t)
{
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}
//softirq.c
void __tasklet_schedule(struct tasklet_struct *t)
{
	unsigned long flags;

	local_irq_save(flags);
	t->next = NULL;
	*__this_cpu_read(tasklet_vec.tail) = t;
	__this_cpu_write(tasklet_vec.tail, &(t->next));
	raise_softirq_irqoff(TASKLET_SOFTIRQ);
	local_irq_restore(flags);
}
EXPORT_SYMBOL(__tasklet_schedule);

test_and_set_bit 函数(原子的)设置tasklet_struct->state 为TASKLET_STATE_SCHED 标志位,然后返回state旧的值,返回为true,说明该tasklet 已经被挂入到tasklet 链表中,返回为false,表示没有持入tasklet 链表,需要调度,调用 __tasklet_schedule。
__tasklet_schedule 把tasklet 挂入 task_vec链表中 ; __tasklet_schedule 调用后不会立刻执行tasklet (从源码中可以看出 tasklet_schedule 只是对tasklet_struct 结构体设置 TASKLET_STATE_SCHED 标志位,只要tasklet 还没有执行,驱动程序多次调用tasklet_schedule也不起作用),需要等到软中断执行时才有机会运行,tasklet 挂在哪个cpu的tasklet_vec链表,那么哪个cpu的软中断来执行。

关于test_and_set_bit 的实现

//在arch/arm/include/asm/bitops.h 
#define ATOMIC_BITOP(name,nr,p)		_##name(nr,p)
#define test_and_change_bit(nr,p)	ATOMIC_BITOP(test_and_change_bit,nr,p)

转换后为_test_and_change_bit 的函数,该函数是汇编写的,源码如下

//arch/arm/lib 
#include <linux/linkage.h>
#include <asm/assembler.h>
#include "bitops.h"
                .text

testop	_test_and_change_bit, eor, str

testop 为汇编的宏,代码在 arch/arm/lib/bitops.h

/**
 * testop - implement a test_and_xxx_bit operation.
 * @instr: operational instruction
 * @store: store instruction
 *
 * Note: we can trivially conditionalise the store instruction
 * to avoid dirtying the data cache.
 */
	.macro	testop, name, instr, store
ENTRY(	\name		)
UNWIND(	.fnstart	)
	ands	ip, r1, #3
	strneb	r1, [ip]		@ assert word-aligned
	and	r3, r0, #31
	mov	r0, r0, lsr #5
	save_and_disable_irqs ip
	ldr	r2, [r1, r0, lsl #2]!
	mov	r0, #1
	tst	r2, r0, lsl r3
	\instr	r2, r2, r0, lsl r3
	\store	r2, [r1]
	moveq	r0, #0
	restore_irqs ip
	ret	lr
UNWIND(	.fnend		)
ENDPROC(\name		)
	.endm

tasklet 执行

软中断执行时会按照软中断状态 __softirq_pending 来依次执行pending 状态的软中断,当执行到TASKLET_SOFTIRQ类型软中断时,会调用 tasklet_action

执行的链条:exit_irq -> __do_softirq -> tasklet_action

static __latent_entropy void tasklet_action(struct softirq_action *a)
{
	struct tasklet_struct *list;
	/*
	在关中断的情况下,读取tasklet_vec链表到临时链表list中,
	并重新初始化tasklet_vec 链表
	*/
	local_irq_disable();
	list = __this_cpu_read(tasklet_vec.head);
	__this_cpu_write(tasklet_vec.head, NULL);
	__this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head));
	local_irq_enable();

	while (list) {
		struct tasklet_struct *t = list;

		list = list->next;
		/*
		tasklet_trylock 函数设计成一个锁,如果tasklet 已经处于RUNNING状态,即被设置了TASKLET_STATE_RUN标志位,
		tasklet_trylock返回false,表示不能获取该锁
		*/
		if (tasklet_trylock(t)) {
			//检测count 计数是否为0 ,为0则表示tasklet 处理可执行状态
			//tasklet_disable 影响的就是count
			if (!atomic_read(&t->count)) {
				// 清除调试标志TASKLET_STATE_SCHED
				if (!test_and_clear_bit(TASKLET_STATE_SCHED,
							&t->state))
					BUG();
				//tasklet 的执行函数
				t->func(t->data);
				tasklet_unlock(t);
				continue;
			}
			tasklet_unlock(t);
		}
		
		//如果tasklet 已经在其它CPU上执行的情况下,tasklet 返回false,这时会把tasklet
		//重新挂入当前CPU的tasklet_vec链表中,等待下一次触发TASKLET_SOFTIRQ类型的软中断才会被执行
		local_irq_disable();
		t->next = NULL;
		*__this_cpu_read(tasklet_vec.tail) = t;
		__this_cpu_write(tasklet_vec.tail, &(t->next));
		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
		local_irq_enable();
	}
}

static inline int tasklet_trylock(struct tasklet_struct *t)
{
	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
}

static inline void tasklet_disable_nosync(struct tasklet_struct *t)
{
	//见if (!atomic_read(&t->count)) 前面注释所产生的影响
	atomic_inc(&t->count);
	smp_mb__after_atomic();
}

static inline void tasklet_disable(struct tasklet_struct *t)
{
	tasklet_disable_nosync(t);
	tasklet_unlock_wait(t);
	smp_mb();
}

如上述注释中所写,tasklet_trylock 保证了同一个tasklet 只能在一个CPU上运行,不能在多cpu上并行,这与之前文章讲软中断并行不一样,这是tasklet 与其它softirq的差别

tasklet_trylock 函数设计成一个锁,如果tasklet
已经处于RUNNING状态,即被设置了TASKLET_STATE_RUN标志位,tasklet_trylock返回false,表示不能获取该锁

tasklet 使用简单示例

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

char tasklet_data[] = "We use a string; but it could be pointer to a structure";

void tasklet_function(unsigned long data)
{
    printk("%s\n", (char *)data);
    return;
}

DECLARE_TASKLET(my_tasklet, tasklet_function, (unsigned long)tasklet_data);

static int __init my_init(void)
{
    //tasklet_disable(&my_tasklet);
    //printk("tasklet_disable\n");

    tasklet_schedule(&my_tasklet);
    printk("tasklet example\n");
    return 0;
}

void my_exit(void)
{
    tasklet_kill(&my_tasklet);
    printk("tasklet example cleanup\n");
    return;
}

module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("null");
MODULE_LICENSE("GPL");

结论

tasklet 是利用软中断实现的一种下半部机制,本质上是软中断的一种变种,运行在中断上下文中.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux tasklet 的分析与使用 的相关文章

  • 在哪里可以找到所有 C 标准库的源代码?

    我正在寻找所有 C 标准库的完整源代码 也就是说 我正在寻找 stdio h stdlib h string h math h 等的源代码 我想看看它们是如何创建的 我认为这取决于不同的平台 但 Linux 或 Windows 都会受到欢迎
  • 如何修复 /usr/bin/env 参数处理?

    我遇到了一个奇怪的问题 usr bin env 我设计了一个简单的脚本来显示问题 该脚本使用 Ruby 编写 但使用 Python 编写的类似脚本也会发生同样的情况 这是脚本 usr bin env ruby p ARGV 还有一个没有 u
  • 如何在树莓派上更新到最新的 python 3.5.1 版本?

    我昨天拿到了 Raspberry Pi 我已经在尝试用它来编写代码了 我有一个计划在其上运行的程序 但它仅与 Python 版本 3 5 0 或 3 5 1 兼容 并且我在互联网上找到的所有内容似乎都已经过时 与 Python 2 有关 或
  • Linux shell 标题大小写

    我正在编写一个 shell 脚本并有一个如下所示的变量 something that is hyphenated 我需要在脚本中的各个点使用它 如下所示 something that is hyphenated somethingthati
  • /usr/bin/as:无法识别的选项“-EL”

    因此 在为我的1plus手机编译android内核时 经过3天的多次尝试 我放弃了并尝试在这里询问是否有人以前遇到过这个问题 这个错误对我来说有点模糊 但我觉得问题来自于我最近对 GNU Linux 发行版 Gentoo 的更改 它在不应该
  • Docker 容器可以访问 DNS,但无法解析主机

    我在运行 docker 容器时遇到一个有趣的问题 突然间 我无法从容器内解析 DNS 这是一个概要 一切都没有解决 apt get pip 一次性 ping 容器等正在运行docker run it dns 8 8 8 8 ubuntu p
  • Tk 初始化失败:无显示名称且无 $DISPLAY 环境变量

    我试图从 Ubuntu 终端调用 Centos 服务器上的工具 我收到以下错误 Tk 初始化失败 没有显示名称 也没有 DISPLAY 环境变量 请帮我解决这个问题 提前致谢 连接到你的 CentOS 机器ssh Y其中 每man ssh
  • 有没有办法改变vim的默认模式

    有谁知道如何更改vim的默认模式 它的默认模式是命令模式 但是我可以将其更改为插入模式吗 只需将以下行添加到您的 vimrc 中 start Vim s default mode will be changed to Insert mode
  • 如何从powershell获取主机名?

    我如何获得hostname https stackoverflow com q 42014215 262852 for dur来自 powershell PS home thufir powershell gt PS home thufir
  • 终止 ssh 会话会终止正在运行的进程

    我正在使用 ssh 连接到我的 ubuntu 服务器 我使用命令启动编码程序 然而 似乎当我的 ssh 会话关闭时 因为我在进入睡眠状态的笔记本电脑上启动它 有没有办法避免这种情况 当然 阻止我的笔记本电脑休眠并不是永久的解决方案 运行你的
  • 使用 xargs 时如何获取退出代码(并行)

    我制作了一个用于启动并行 rsync 进程的脚本 bin bash LIST 1 DEST DIR 2 RSYNC OPTS 3 echo rsyncing From SRC DIR To DEST DIR RSYNC OPTS RSYNC
  • Bash 脚本错误 [重复]

    这个问题在这里已经有答案了 我想知道下面的脚本有什么错误 我收到错误为 command not foundh line 1 command not foundh line 2 其连续的 我试过添加 但现在工作请告诉我该怎么做 bin bas
  • 第一次如何配置postgresql?

    我刚刚安装了 postgresql 并在安装过程中指定了密码 x 当我尝试做的时候createdb并指定我收到消息的任何密码 createdb 无法连接到数据库 postgres 致命 用户密码身份验证失败 同样适用于createuser
  • 容器上的“container_memory_working_set_bytes”指标和 OOM-killer 之间有什么关系?

    我试图找出并理解 OOM killer 如何在容器上工作 为了弄清楚这一点 我读了很多文章 发现 OOM killer 会根据oom score And oom score是由oom score adj以及该进程的内存使用情况 有两个指标c
  • 如何在Linux中获取带有图标的活动应用程序

    我想找到一种方法获取活动应用程序的列表及其名称和图标 实际上 我正在使用此命令来获取所有活动进程 wmctrl lp 示例输出 0x03800002 0 3293 user notebook XdndCollectionWindowImp
  • 64位版本的adb和fastboot?

    我在 Debian 7 3 x64 已完全修补 上发现了以下错误 我很确定这是因为adb即使在其 SDK 工具的 64 位发行版中也是 32 位 which adb opt android sdk platform tools adb op
  • 使用多个 NIC 广播 UDP 数据包

    我正在 Linux 中为相机控制器构建嵌入式系统 非实时 我在让网络做我想做的事情时遇到问题 该系统有 3 个 NIC 1 个 100base T 和 2 个千兆端口 我将较慢的连接到相机 这就是它支持的全部 而较快的连接是与其他机器的点对
  • 是否可以为我的 Linux 函数复制命令的制表符补全?

    假设我有一个名为的 bash shell 函数magic 我想定义一个制表符补全功能 magic这将允许magic搭载任何给定命令的选项卡完成功能 如果可用 换句话说 我想要magic能够做这样的事情 magic git
  • 未找到 DEADLINE 调度策略

    我想在 C 中实现 DEADLINE 调度策略 我知道该功能已实现Linux 3 14 10我正在使用 Ubuntu 14 04Linux 3 17 0 031700 lowlatency 201410060605 SMP PREEMPT这
  • 在linux中将包含word的行从一个文件复制到另一个文件

    我想复制包含某些单词的行file1 to file2 Suppose file1 ram 100 ct 50 gopal 200 bc 40 ravi 50 ct 40 krishna 200 ct 100 file2应该只有包含 ct 的

随机推荐

  • VUE前端实现token的无感刷新

    前言 说实话 这个其实没啥好讲的 要说有复杂度的话 也主要是在后端 实现token无感刷新对于前端来说是一项十分常用的技术 其本质都是为了优化用户体验 当token过期时不需要用户调回登录页重新登录 而是当token失效时 进行拦截 发送刷
  • Spring Boot 整合MyBatis 和 Spring Boot 整合MyBatis-Plus

    目录 Spring Boot 整合MyBatis 代码 配置实现 创建数据库和表 使用灵活的方式创建maven 创建resources application yml 配置数据源参数 并完成Spring Boot 项目启动测试 测试Drui
  • 5种获取JavaScript时间戳函数的方法

    来源 https www fly63 com 一 JavasCRIPT时间转时间戳 JavaScript获得时间戳的方法有五种 后四种都是通过实例化时间对象new Date 来进一步获取当前的时间戳 JavaScript处理时间主要使用时间
  • 排序算法整理

    冒泡排序 bubble sort public static void bubbleSort int array int n int i 0 loop int j 0 element index while i lt n for j 0 j
  • xshell的快捷键

    删除 ctrl d 删除光标所在位置上的字符相当于VIM里x或者dl ctrl h 删除光标所在位置前的字符相当于VIM里hx或者dh ctrl k 删除光标后面所有字符相当于VIM里d shift ctrl u 删除光标前面所有字符相当于
  • Linux网络管理-配置网卡

    目录 一 概念 二 配置网卡 2 1 命令行配置 2 1 1 查询网卡 2 1 2 配置网卡 2 2查询IP地址 2 3 查询DNS 三 配置两台机器通信 3 1 查看参数 3 2 进入配置环境 3 3 重启网卡 四 主机改名 五 重点 扩
  • ChatGPT写文书再次翻车,行文寡淡没有灵魂一眼假!

    留学申请文书是每个渴望出国深造的学子都会面临的一道门槛 近年来 随着人工智能ChatGPT的迅猛发展 文能写文章 武能改Bug AI代写留学文书逐渐成为一种趋势 不少人直呼申请文书有救了 然而 这种趋势是否真的有益呢 或许 我们应该对这种现
  • ‘sleep_for’ is not a member of ‘std::this_thread’ 报错是因为版本太低

    1 GCC编译器 从编译器GCC4 8 X的版本完全支持 1 目前C 11特性 之前成为C 0X特性 从GCC4 3的后续版本中逐步对C 11进行支持 2 从官方信息可以看到 目前从完全对C 11特性进行支持的是从编译器GCC4 8 X的版
  • 虚拟数字人和GPT-4的结合,能否迎来新爆发?

    最近 ChatGPT一直在互联网上狂飙 从 去年11月底推出到月活过亿 仅花了2个月的 时间 它既可以拥有美国的医学牌照 参加司法考试 又能写小说 编代码 查资料 还可 以陪你闲聊 你问它什么话题 它都能对答如流 有模有样 3月13日 Ch
  • python模块openpyxl常用指令

    1 加载xlsx文件 from openpyxl import load workbook wb load workbook xlsx file 2 获取加载xlsx文件有哪些sheets 1 遍历方法 for sheet in wb pr
  • 【软件教程】如何让vscode连接ssh时免密登录

    准备软件 客户机安装vscode vscode官网https code visualstudio com 客户机和服务器配置ssh 确保能够连接 VSCode ssh免密登录教程 一 在Client客户机生成ssh密钥对 打开客户机的cmd
  • bat获取所有的参数

    bat默认只能获取到1 9个参数 分别用 1 2 9引用 如果传给bat的参数大于9个 就必须用shift 工作需要 要写个bat脚本 获取所有的参数 再将所有的参数传给Java 代码如下 allparam就是获取到的所有参数字符串 ech
  • Window 窗口属性及嵌入窗口到D3D渲染窗口顶层

    Window窗口有很多属性 可以通过设定window的style和ex style中知道 这些属性有时候在实现某些效果的时候 是非常非常重要 以前都没有怎么详细了解 只是在用到对应的API时看一下 根本没有详细深入 这里想记录一下最近工作上
  • Python 创建Windows窗口(GUI)

    创建Windows窗口 GUI py 基本的四要素 import tkinter 导入tkinter模块 root tkinter Tk 创建Window窗口对象 root title 我的第一个GUI程序 窗口标题 root mainlo
  • 屏幕截图的实现和源代码

    最近打算写一些入门相关的小应用程序开发实例 个人感觉学习程序开发 其关键的一步就是阅读源代码 RTFSC 呵呵 然后尝试自己动手编写 这里所谓的自己动手编写并不是让你照着源代码一句话一句的敲 也不是复制粘贴 而是阅读了源代码以后 学习其中的
  • 使用vscode 连接服务器 进行深度学习代码调试

    博主本来在Win上已经配好环境了 但是在跑代码的过程中 因为tensor拼接得太大了 导致笔记本内存不足 因此需要到服务器上跑 为什么选择vscode 如果直接用xshell连接服务器 在命令行运行py文件 不是很直观 也不能debug 还
  • Linux HugePage

    1 闲聊 有一段时间 数据库上出现过CPU消耗非常高的问题 最后分析到了Linux HugePage 发现自己对这一块都没什么了解 于是做了 些了解 Linux 下的大页分为两种类型 标准大页 Huge Pages 和透明大页 Transp
  • ZK实现SASL认证+Kafka连接ZK

    ZK实现SASL认证 Kafka连接ZK 关键词 zk sasl kfaka 未授权认证 参考文档 搭建Kafka集群时 对ZooKeeper认证与权限控制 http ohmycat me 2019 05 08 kafka with zoo
  • VUE element-ui之table表格中嵌套输入框,且输入框失焦自动勾选当前行

    步骤 表格中直接插槽法
  • linux tasklet 的分析与使用

    linux tasklet 的分析与使用 目录 linux tasklet 的分析与使用 tasklet 源码分析 tasklet shedule 调度的分析 tasklet 执行 tasklet 使用简单示例 结论 tasklet 是利用