LWN:tasklet要被终结了!

本文讨论了内核开发中如何控制任务执行时间,特别关注了tasklet的去留和新工作队列WQ_BH的引入,以解决中断处理中的延迟问题。作者提到6.9内核版本可能见证taskletAPI的淘汰和高性能工作队列的普及。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关注了就能看到更多这么棒的文章哦~

The end of tasklets

By Jonathan Corbet
February 5, 2024
Gemini translation
https://lwn.net/Articles/960041/

在内核开发中,常见的困难在于控制 何时 让特定的任务完成。内核代码经常在一些动作(例如休眠或调用文件系统)无法进行的环境中执行。虽然可能执行其他动作,但可能会妨碍内核及时执行更重要的任务。内核社区开发了许多延迟执行的机制,旨在确保每一个任务都在正确的时间得到处理。其中一个机制 tasklet 已经有很多年都被考虑移除了,可能在不久的将来就会落实。

延迟执行经常有必要的一个环境就是中断处理程序(interrupt handler)。中断会把 CPU 从当时正在执行的任何任务中打断,要求必须尽快地处理中断代码;在中断处理程序中甚至不可能休眠。因此,中断处理程序通常仅记录需要执行的操作,然后安排在更宽松的环境中执行实际工作。这种延后执行措施有多种选项可以实现:

  • 线程中断处理程序(Threaded interrupt handler) 。这种机制源于实时代码树,在 2009 年的 2.6.30 版本中合并到内核;它会导致驱动程序的大部分中断处理程序在一个单独的内核线程中运行。线程处理程序由于在进程环境中运行,因此允许休眠;如有需要的话,系统管理员还可以调整它们的优先级。

  • 工作队列 最初 添加 在 2.5 开发系列中,从那时起得到了很大的增强。驱动程序可以创建一个 work,其中包含一个函数指针和一些数据,并将其提交到工作队列中。在未来的某个时间,该函数将使用提供的数据来得到调用;同样,此调用将在进程环境中发生。还有各种具备不同性能特性的工作队列,如有需要,任何一个子系统都可以创建它们自己的私有工作队列。

  • 软件中断(或“下半部分”) 这种机制是内核中最古老的机制之一;它从早期的 Unix 系统中获得了灵感。软件中断是一个专用的处理程序,通常在硬件中断完成之后或返回到用户空间之前,在原子上下文中运行。多年来人们一直希望移除此机制,因为它会在内核中产生意外的延迟,但它现在仍然存在;添加一个新的(直接)软件中断的使用代码会遇到很大的阻力。有关软件中断的更多信息,请参阅 LWN 相关文章。

  • Tasklet ,与工作队列一样,tasklet 是安排在未来某个时间调用函数的一种方法。目前,tasklet 函数将通过软件中断进行调用,并在原子上下文中运行。Tasklet 从 2.3 开发系列就有了;多年来,它们也被列入淘汰行列 很多年了,但迄今为止还没能达到目的。

线程中断处理程序和工作队列被认为是现代内核代码中延迟工作的首选机制,但其他 API 被证明很难被逐步淘汰。特别是 tasklet,它们保留下来是因为它们提供的延迟比工作队列小,由于工作队列必须通过 CPU 调度程序,因此执行延迟 work 可能需要更长的时间。

最近,Mikulas Patocka 在 tasklet API 中遇到了问题。Tasklet 由 struct tasklet_struct 定义,其中包含回调函数的地址和相关信息。tasklet 子系统需要能够操作该结构,并且可以在 tasklet 函数完成执行并返回后这样做。如果 tasklet 函数本身想释放该结构,这可能会导致问题,例如对于不会再次调用的单次 tasklet。tasklet 子系统可能会转而写入一个已被释放并分配用于其他用途的结构,谁都知道将导致不良后果。

Patocka 试图通过添加一个新的“单次(one-shot)”tasklet 变体来修复这个问题,在其中 tasklet 子系统会承诺在 tasklet 自己运行后不去动 tasklet_struct 结构。然而,Linus Torvalds 不喜欢这个补丁;他说,tasklet 不应该以这种方式使用。他说,工作队列设计得更好,更适合这种用例 — 除了它们可能引入的额外延迟。所以,他建议,正确的方法可能是引入一种新类型的工作队列:

我认为,如果我们引入一个更像 tasklet(因为它在软中断环境中运行)的工作队列,但没有 tasklet 的接口设计上的错误,那么许多现有的工作队列用户可能会认为这正是他们想要的。

工作队列维护者 Tejun Heo 按照这个思路执行了;从而得到 一组补丁 来添加了一种新的工作队列类型 WQ_BH ,它具有 Torvalds 所描述的语义。提交到 WQ_BH 工作队列的 work 将在同一个 CPU 上的原子上下文中快速运行。

有趣的是,这些 work 现在由 tasklet 运行,暂时是这样。由于担心 WQ_BH work 与现有 tasklet 之间优先级反转的问题,Heo 选择让 tasklet 子系统来控制。然而,该补丁系列将许多 tasklet 用户转换为了新的工作队列类型,而且很明显计划最终把其他所有地方都转换掉。这可能需要一段时间;内核中有超过 500 个 tasklet 使用位置。不过,一旦完成转换,就有可能直接从软件中断来运行 WQ_BH 工作队列,并完全移除 tasklet API。

当然,当前的实现中仍然保留了软件中断;移除该子系统将是另一项工作。Sebastian Andrzej Siewior 抱怨 使用软件中断的情况,他更愿意看到 tasklet 用户迁移到线程中断处理程序或常规的工作队列。但是,正如 Heo 回答 的那样,在需要最短延迟的情况下没法这样做。似乎总会有一个不需要调度的延迟工作机制,无论实时开发者多么不乐意看到。

Heo 将该补丁系列 标记 为针对 6.9 内核版本,这意味着它需要在 3 月中旬的合并窗口准备就绪。对于像这样的重大新特性来说,这相对算是比较快的了,但它使用一个已建立良好的内核 API 来淘汰开发人员多年来一直想摆脱的一个子系统。因此,这项特殊工作有可能不会被推迟到下一个内核周期。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

6d503bc054d5b4cd05098c49b3d18865.jpeg

资源下载链接为: https://pan.quark.cn/s/67c535f75d4c C语言作为一门基础且强大的编程语言,在底层系统编程和算法实现方面表现卓越,其效率与灵活性备受推崇。其中,“用指针实现的C语言排序算法”这一主题,融合了C语言的核心概念——指针,以及数据结构和算法的基础知识。指针是C语言的一大特色,它能够直接操作内存地址,从而为高效的数据操作提供了有力支持。在排序算法中,指针通常被用作迭代工具,用于遍历数组或链表,进而改变元素的顺序。 常见的排序算法,如冒泡排序、选择排序、插入排序、快速排序和归并排序等,都可以借助指针来实现。具体而言: 冒泡排序:通过交换相邻元素来实现排序。在C语言中,可以定义一个指向数组的指针,通过指针的递增或递减操作来遍历数组,比较相邻元素并在必要时进行交换。 选择排序:每次从剩余部分中找到最小(或最大)元素,然后将其与第一个未排序的元素进行交换。指针可用于标记已排序和未排序部分的边界。 插入排序:将元素插入到已排序的部分,以保持有序性。可以使用指针跟踪已排序部分的末尾,并在找到合适位置后进行插入操作。 快速排序:采用分治策略,选择一个“基准”元素,将数组分为两部分,一部分的所有元素都小于基准,另一部分的所有元素都大于基准。这一过程通常通过递归来实现,而基准元素的选择和划分过程往往涉及指针操作。 归并排序:将数组分为两半,分别对它们进行排序,然后再进行合并。在C语言中,这通常需要借助动态内存分配和指针操作来处理临时数组。 在实现这些排序算法时,理解指针的用法极为关键。指针不仅可以作为函数参数传递,从而使排序算法能够作用于任何可寻址的数据结构(如数组或链表),而且熟练掌握指针的解引用、算术运算和比较操作,对于编写高效的排序代码至关重要。然而,需要注意的是,尽管指针提供了直接操作内存的便利,但不当使用可能会引发错误,例如内存泄漏、空指针
资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 在电子设备设计中,多功能按键的实现是至关重要的技术,它能够为用户提供丰富多样的交互方式,比如单击、双击和长按等操作。本文将深入探讨如何设计一个多功能按键系统,涵盖按键识别逻辑、接口函数设计,以及如何避免使用定时器。 首先,我们需要理解多功能按键的基本原理。在硬件层面,按键通常是通过连接到微控制器(MCU)的一个输入引脚来实现的。当按键未被按下时,该引脚保持高电平;而当按键按下时,引脚会与地短路,变为低电平。因此,通过检测该引脚的状态,就可以判断按键是否被按下。 接下来,我们来探讨如何识别不同的按键操作。单击是最基本的操作,通常定义为按键快速按下并释放。双击则是在短时间内连续两次单击,而长按则是按键被按下并持续一段时间。为了实现这些功能,我们需要在软件中加入一些延时处理。例如,当我们检测到按键按下事件后,可以启动一个短暂的延时。如果在此期间再次检测到按键按下,则判断为双击;如果延时结束仍未检测到第二次按下,则认为是单击。对于长按操作,可以设定一个较长的延时,如果按键在这段时间内一直保持按下状态,则识别为长按。 接口函数设计是软件工程中的重要环节。对于多功能按键,我们可以设计以下核心接口: void Key_Init(void):初始化按键,设置中断或轮询模式,并设置初始状态。 uint8_t Key_Scan(void):扫描按键状态,返回当前按键的操作类型,例如,0表示无操作,1表示单击,2表示双击,3表示长按。 void Key_Callback(uint8_t key_event):这是一个注册的回调函数,根据Key_Scan()返回的事件类型执行相应的操作。 在实际应用中,为了避免频繁的中断请求和降低功耗,我们有时会选择使用延时而非定时器。延时函数可以通过循环计数实现,例如,使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值