中断处理的tasklet(小任务)机制-不过如此

中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。因此,内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两部分:上半部(top half)和下半部(bottom half),上半部(就是中断服务程序)内核立即执行,而下半部(就是一些内核函数)留着稍后处理。

        首先,一个快速的“上半部”来处理硬件发出的请求,它必须在一个新的中断产生之前终止。通常,除了在设备和一些内存缓冲区(如果你的设备用到了DMA,就不止这些)之间移动或传送数据,确定硬件是否处于健全的状态之外,这一部分做的工作很少。

        下半部运行时是允许中断请求的,而上半部运行时是关中断的,这是二者之间的主要区别。

        但是,内核到底什时候执行下半部,以何种方式组织下半部?这就是我们要讨论的下半部实现机制,这种机制在内核的演变过程中不断得到改进,在以前的内核中,这个机制叫做bottom half(简称bh),在2.4以后的版本中有了新的发展和改进,改进的目标使下半部可以在多处理机上并行执行,并有助于驱动程序的开发者进行驱动程序的开发。下面主要介绍常用的小任务(Tasklet)机制及2.6内核中的工作队列机制。除此之外,还简要介绍2.4以前内核中的下半部和任务队列机制。

1. 小任务机制  
        这里的小任务是指对要推迟执行的函数进行组织的一种机制。其数据结构为tasklet_struct,每个结构代表一个独立的小任务,其定义如下:
struct tasklet_struct {
struct tasklet_struct *next;        /*指向链表中的下一个结构*/
     unsigned long state;            /* 小任务的状态 */
     atomic_t count;    /* 引用计数器 */
     void (*func) (unsigned long);            /* 要调用的函数 */
     unsigned long data;           /* 传递给函数的参数 */
};
        结构中的func域就是下半部中要推迟执行的函数 ,data是它唯一的参数。

        State域的取值为TASKLET_STATE_SCHED或TASKLET_STATE_RUN。TASKLET_STATE_SCHED表示小任务已被调度,正准备投入运行,TASKLET_STATE_RUN表示小任务正在运行。TASKLET_STATE_RUN只有在多处理器系统上才使用,单处理器系统什么时候都清楚一个小任务是不是正在运行(它要么就是当前正在执行的代码,要么不是)。

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

2. 声明和使用小任务
        大多数情况下,为了控制一个寻常的硬件设备,小任务机制是实现下半部的最佳选择。小任务可以动态创建,使用方便,执行起来也比较快。

        我们既可以静态地创建小任务,也可以动态地创建它。选择那种方式取决于到底是想要对小任务进行直接引用还是一个间接引用。如果准备静态地创建一个小任务(也就是对它直接引用),使用下面两个宏中的一个:
DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)

        这两个宏都能根据给定的名字静态地创建一个tasklet_struct结构。当该小任务被调度以后,给定的函数func会被执行,它的参数由data给出。这两个宏之间的区别在于引用计数器的初始值设置不同。第一个宏把创建的小任务的引用计数器设置为0,因此,该小任务处于激活状态。另一个把引用计数器设置为1,所以该小任务处于禁止状态。例如:
DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev);

        这行代码其实等价于
struct tasklet_struct my_tasklet = { NULL, 0, ATOMIC_INIT(0),tasklet_handler, dev};

        这样就创建了一个名为my_tasklet的小任务,其处理程序为tasklet_handler,并且已被激活。当处理程序被调用的时候,dev就会被传递给它。

3. 编写自己的小任务处理程序
        小任务处理程序必须符合如下的函数类型:
void tasklet_handler(unsigned long data)

        由于小任务不能睡眠,因此不能在小任务中使用信号量或者其它产生阻塞的函数。但是小任务运行时可以响应中断。

4. 调度自己的小任务
        通过调用tasklet_schedule()函数并传递给它相应的tasklt_struct指针,该小任务就会被调度以便适当的时候执行:
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的长指针。在小任务重新调度它自身的时候,从挂起的队列中移去已调度的小任务会很有用。这个函数首先等待该小任务执行完毕,然后再将它移去。

5. tasklet的简单用法

        下面是tasklet的一个简单应用, 以模块的形成加载。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>

static struct tasklet_struct my_tasklet;

static void tasklet_handler (unsigned long data)
{
        printk(KERN_ALERT “tasklet_handler is running.n”);
}

static int __init test_init(void)
{
        tasklet_init(&my_tasklet, tasklet_handler, 0);
        tasklet_schedule(&my_tasklet);
        return 0;
}

static void __exit test_exit(void)
{
        tasklet_kill(&tasklet);
        printk(KERN_ALERT “test_exit running.n”);
}
MODULE_LICENSE(“GPL”);

module_init(test_init);
module_exit(test_exit);

        从这个例子可以看出,所谓的小任务机制是为下半部函数的执行提供了一种执行机制,也就是说,推迟处理的事情是由tasklet_handler实现,何时执行,经由小任务机制封装后交给内核去处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469282.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Pytorch神经网络理论篇】 29 图卷积模型的缺陷+弥补方案

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络实战案例】22 基于Cora数据集实现图注意力神经网络GAT的论文分类

注意力机制的特点是&#xff0c;它的输入向量长度可变&#xff0c;通过将注意力集中在最相关的部分来做出决定。注意力机制结合RNN或者CNN的方法。 1 实战描述 【主要目的&#xff1a;将注意力机制用在图神经网络中&#xff0c;完成图注意力神经网络的结构和搭建】 1.1 实现…

用OC和Swift一起说说二叉树

前言&#xff1a; 一&#xff1a;在计算机科学中&#xff0c;二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”&#xff08;left subtree&#xff09;和“右子树”&#xff08;right subtree&#xff09;。二叉树常被用于实现二叉查找树和二叉堆。二&#xf…

【Pytorch神经网络理论篇】 30 图片分类模型:Inception模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

mtk pwmlinux timer

pwm控制还是有很多要注意的地方 附上驱动的代码 /** drivers/leds/leds-mt65xx.c** This file is subject to the terms and conditions of the GNU General Public* License. See the file COPYING in the main directory of this archive for* more details.** Hydrodent …

【Pytorch神经网络理论篇】 31 图片分类模型:ResNet模型+DenseNet模型+EffcientNet模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

CentOS7 编译安装golang和rpm安装golang

编译安装 1、下载golang二进制安装包&#xff1a; https://storage.googleapis.com/golang/go1.9.linux-amd64.tar.gz 2、解压安装包到指定目录&#xff0c;此处以解压到/usr/local目录下为例&#xff1a; 1 tar -C /usr/local -xzf ../packages/go1.8.linux-amd64.tar.gz 3、在…

Class_fileAndroid应用调用方法

java代码调用 fos.write这里面是byte类型的 + private static final String LEDBLPATH="/sys/class/hdyrodent_charger_led/brightness"; + private final void SetChargerLedBrightness(String path,int brightness) + { + try{ + …

【Pytorch神经网络理论篇】 32 PNASNet模型:深层可分离卷积+组卷积+空洞卷积

1 PNASNet模型简介 PNASNet模型是Google公司的AutoML架构自动搜索所产生的模型&#xff0c;它使用渐进式网络架构搜索技术&#xff0c;并通过迭代自学习的方式&#xff0c;来寻找最优网络结构。即用机器来设计机器学习算法&#xff0c;使得它能够更好地服务于用户提供的数据。该…

s5k5e2ya MIPI 摄像头调试

1、驱动移植的话按照我之前的文章来做 驱动里面注意是几路的lane,一般mipi的话是差分信号&#xff0c;2路和4路是比较常见的。2、mipi波形 很明显上面的波形是不正确的。dp dn有一个都成了正弦波了。 首先&#xff0c;我们要找一下正确的波形 正确的波形应该是DP和DN不会同时…

css那些事儿4 背景图像

background:背景颜色&#xff0c;图像&#xff0c;平铺方式&#xff0c;大小&#xff0c;位置 能够显示背景区域即为盒子模型的填充和内容部分&#xff0c;其中背景图像将会覆盖背景颜色。常见的水平或垂直渐变颜色背景通常使用水平或垂直渐变的背景图像在水平或垂直方向平铺&a…

用Android UEventObserver监听内核event

很多时候我们在框架上层需要知道内核中某些事件的状态&#xff0c;用设备的show属性是可以供上层来查询&#xff0c;但是这需要上层设定一个较耗资源的循环。如果用UEventObserver就可以监听内核event&#xff0c;它是android Java层利用uevent与获取Kernel层状态变化的机制。 …

【Pytorch神经网络实战案例】23 使用ImagNet的预训练模型识别图片内容

1 案例基本工具概述 1.1 数据集简介 Imagenet数据集共有1000个类别&#xff0c;表明该数据集上的预训练模型最多可以输出1000种不同的分类结果。 Imagenet数据集是目前深度学习图像领域应用得非常多的一个领域&#xff0c;关于图像分类、定位、检测等研究工作大多基于此数据…

杂谈转载

一、什么是运行时&#xff08;Runtime&#xff09;? 运行时是苹果提供的纯C语言的开发库&#xff08;运行时是一种非常牛逼、开发中经常用到的底层技术&#xff09;二、运行时的作用&#xff1f; 能获得某个类的所有成员变量能获得某个类的所有属性能获得某个类的所有方法交换…

Linux中的工作队列

工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行&#xff0c;因此工作队列的优势就在于它允许重新调度甚至睡眠。 工作队列是2.6内核开始引入的机制&#xff0c;在2.6.20之后…

【Pytorch神经网络实战案例】24 基于迁移学习识别多种鸟类(CUB-200数据集)

1 迁移学习 在实际开发中&#xff0c;常会使用迁移学习将预训练模型中的特征提取能力转移到自己的模型中。 1.1 迁移学习定义 迁移学习指将在一个任务上训练完成的模型进行简单的修改&#xff0c;再用另一个任务的数据继续训练&#xff0c;使之能够完成新的任务。 1.1.1 迁…

linux工作队列

这里对Linux的工作队列(work_queue)不做深层次的挖掘&#xff0c;只对如何使用它以及一些简单的结构做简单地介绍。 Linux源代码(3.0.8)中和工作队列(work_queue)相关的结构主要在 include/linux/workqueue.h这个头文件中&#xff0c;这里就不摘抄了。这里就直接给出例子代码…

【Pytorch神经网络理论篇】 33 基于图片内容处理的机器视觉:目标检测+图片分割+非极大值抑制+Mask R-CNN模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

linux inputuevent使用

input 输入子系统 在应用层使用的时候&#xff0c;容易出现找不到UEventObserver.java 这时候就要导入jar包 导入classes.jar这个jar包 weiqifaweiqifa-Inspiron-3847:~/weiqifa/tm100$ ls out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/ classes classes…

linq中给字段添加别名

linq 是我们在查询中经常回用到的一种形式,比如我们创建一个类,然后List<添加> 并绑定到表格中public class Modeltest{string id;public string Id{get { return id; }set { id value; }}string pwd;public string Pwd{get { return pwd; }set { pwd value; }}string…