Linux驱动开发杂记(0x15) - tasklet

2024-06-09 06:18

本文主要是介绍Linux驱动开发杂记(0x15) - tasklet,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

为了提高系统的响应能力和并发能力,Linux将中断处理分了上半部和下半部。当一个中断产生,调用该中断对应的处理程序(上半部),然后告诉系统,对应的后半部可以执行了,中断处理程序立即返回,下半部会在合适的时机由操作系统调用。这样一来就大大的减少了中断处理所需要的时间。

tasklet是中断处理下半部分最常用的一种方法,驱动程序一般先申请中断,在中断处理函数内完成中断上半部分的工作后调用tasklet。

一、tasklet的特点

  1. tasklet只可以在一个CPU上同步地执行,不同的tasklet可以在不同地CPU上同步地执行。
  2. tasklet的实现是建立在两个软件中断的基础之上的,即HI_SOFTIRQ和TASKLET_SOFTIRQ,本质上没有什么区别,只不过HI_SOFTIRQ的优先级更高一些
  3. 由于tasklet是在软中断上实现的,所以像软中断一样不能睡眠、不能阻塞,处理函数内不能含有导致睡眠的动作,如减少信号量、从用户空间拷贝数据或手工分配内存等。
  4. 一个 tasklet 能够被禁止并且之后被重新使能; 它不会执行直到它被使能的次数与被禁止的次数相同.
  5. tasklet的串行化使tasklet函数不必是可重入的,因此简化了设备驱动程序开发者的工作。
  6. 每个cpu拥有一个tasklet_vec链表,具体是哪个cpu的tasklet_vec链表,是根据当前线程是运行在哪个cpu来决定的。

二、tasklet结构体

struct tasklet_struct {struct tasklet_struct 	*next;		/*指向链表中的下一个结构*/unsigned long 			state;		/* 小任务的状态 */atomic_t 				count;		/* 引用计数器 */void (*func) (unsigned long);		/* 要调用的函数 */unsigned long 			data;		/* 传递给函数的参数 */
}
  • State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度,正准备投入运行,TASKLET_STATE_RUN表示小任务正在运行。

  • Count域是小任务的引用计数器。如果它不为0,则小任务被禁止,不允许执行;只有当它为零,小任务才被激活,并且在被设置为挂起时,小任务才能够执行。

三、tasklet的定义

tasklet既可以静态创建也可以动态创建。

1、静态创建

定义变量名为name的tasklets_struct变量,并初始化调用函数为func,参数为data,使能tasklet。

DECLARE_TASKLET(name, func, data);
#define DECLARE_TASKLET(name, func, data) \struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

定义变量名为name的tasklets_struct变量,并初始化调用函数为func,参数为data,禁止tasklet。

DECLARE_TASKLET_DISABLED(name, func, data)#define DECLARE_TASKLET_DISABLED(name, func, data) \struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

2、动态创建

先定义struct tasklet_struct name;然后初始化

void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
{t->next = NULL;              //t->state = 0;                //设置为未调度 未运行  atomic_set(&t->count, 0);    //默认使能t->func = func;              //调用函数t->data = data;              //调用函数参数
}

四、调度tasklet

通过调用tasklet_schedule()函数并传递给它相应的tasklt_struct指针,该小任务就会被调度以便适当的时候执行:

static inline void tasklet_schedule(struct tasklet_struct *t)tasklet_schedule(&my_tasklet);  /*把 my_tasklet 标记为挂起 */

在小任务被调度以后,只要有机会它就会尽可能早的运行。在它还没有得到运行机会之前,如果一个相同的小任务又被调度了,那么它仍然只会运行一次。
可以调用tasklet_disable()函数来禁止某个指定的小任务。如果该小任务当前正在执行,这个函数会等到它执行完毕再返回。调用tasklet_enable()函数可以激活一个小任务,如果希望把以DECLARE_TASKLET_DISABLED()创建的小任务激活,也得调用这个函数,如:

tasklet_disable(&my_tasklet);     /* 小任务现在被禁止,这个小任务不能运行 */
tasklet_enable(&my_tasklet);    /*  小任务现在被激活 */

也可以调用tasklet_kill()函数从挂起的队列中去掉一个小任务。该函数的参数是一个指向某个小任务的tasklet_struct的长指针。在小任务重新调度它自身的时候,从挂起的队列中移去已调度的小任务会很有用。这个函数首先等待该小任务执行完毕,然后再将它移去。

五、tasklet相关函数

void tasklet_disable(struct tasklet_struct *t);

这个函数禁止给定的 tasklet. tasklet 可能仍然被 tasklet_schedule 调度, 但是它的执行被延后直到这个 tasklet 被再次使能. 如果这个 tasklet 当前在运行,这个函数忙等待直到这个 tasklet 退出; 因此, 在调用 tasklet_disable 后, 你可以确保这个 tasklet 在系统任何地方都不在运行.

void tasklet_disable_nosync(struct tasklet_struct *t);

禁止这个 tasklet, 但是没有等待任何当前运行的函数退出. 当它返回, 这个tasklt 被禁止并且不会在以后被调度直到重新使能, 但是它可能仍然运行在另一个 CPU 当这个函数返回时.

void tasklet_enable(struct tasklet_struct *t);

使能一个之前被禁止的 tasklet. 如果这个 tasklet 已经被调度, 它会很快运行.一个对 tasklet_enable 的调用必须匹配每个对 tasklet_disable 的调用, 因为内核跟踪每个 tasklet 的"禁止次数".

void tasklet_schedule(struct tasklet_struct *t);

调度 tasklet 执行. 如果一个 tasklet 被再次调度在它有机会运行前, 它只运行一次. 但是, 如果他在运行中被调度, 它在完成后再次运行; 这保证了在其他事件被处理当中发生的事件收到应有的注意. 这个做法也允许一个 tasklet 重新调度它自己.

void tasklet_hi_schedule(struct tasklet_struct *t);

调度 tasklet 在更高优先级执行. 当软中断处理运行时, 它处理高优先级tasklet 在其他软中断之前, 包括"正常的" tasklet. 理想地, 只有具有低响应周期要求( 例如填充音频缓冲 )应当使用这个函数, 为避免其他软件中断处理引入的附加周期. 实际上, /proc/jitasklethi 没有显示可见的与 /proc/jitasklet 的区别.

void tasklet_kill(struct tasklet_struct *t);

这个函数确保了这个 tasklet 没被再次调度来运行; 它常常被调用当一个设备正被关闭或者模块卸载时. 如果这个 tasklet 被调度来运行, 这个函数等待直到它已执行. 如果这个 tasklet 重新调度它自己, 你必须阻止在调用 tasklet_kill前它重新调度它自己, 如同使用 del_timer_sync.

六、tasklet使用模板

/* 定义tasklet和底半部函数并将它们关联 */
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);/* 中断处理底半部 */
void xxx_do_tasklet(unsigned long)
{//...
}/* 中断处理顶半部 */
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{//...tasklet_schedule(&xxx_tasklet);//...
}/* 设备驱动模块加载函数 */
int __init xxx_init(void)
{//.../* 申请中断 */result = request_irq(xxx_irq, xxx_interrupt, 0, "xxx", NULL);//...return IRQ_HANDLED;
}/* 设备驱动模块卸载函数 */
void __exit xxx_exit(void)
{//.../* 释放中断 */free_irq(xxx_irq, xxx_interrupt);//...
}

这篇关于Linux驱动开发杂记(0x15) - tasklet的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044406

相关文章

一文教你如何解决Python开发总是import出错的问题

《一文教你如何解决Python开发总是import出错的问题》经常朋友碰到Python开发的过程中import包报错的问题,所以本文将和大家介绍一下可编辑安装(EditableInstall)模式,可... 目录摘要1. 可编辑安装(Editable Install)模式到底在解决什么问题?2. 原理3.

Linux系统调试之ltrace工具使用与调试过程

《Linux系统调试之ltrace工具使用与调试过程》:本文主要介绍Linux系统调试之ltrace工具使用与调试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、ltrace 定义与作用二、ltrace 工作原理1. 劫持进程的 PLT/GOT 表2. 重定

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3