Linux 驱动 中断(二)

中断下半部

在 Linux 内核中,中断下半部(也称为中断下半场)是指在中断服务程序(Top Half)执行完毕后,在上下文之外延迟执行的一些操作。中断下半部通常用于处理那些不适合在中断上下文中立即执行的任务,以保持中断服务程序的快速响应。

中断下半部可以通过以下几种机制来实现:

1、Tasklet,一种内核机制,用于在延迟上下文中执行轻量级的任务。Tasklet 通常在中断服务程序的上下文中调度,并在延迟上下文中执行。是在禁止所有中断的情况下进行的,因此它们可以安全地访问共享的数据结构和资源。

2、工作队列(Workqueue),工作队列是一种内核机制,用于在延迟上下文中异步执行较为耗时的任务。工作队列可以在系统的后台执行,并且可以并发执行多个任务。是由内核线程来完成的,因此可以执行任意复杂度的操作,并且不会阻塞其他内核活动。

3、软中断(SoftIRQ),软中断是一种内核机制,用于在延迟上下文中执行一些较为复杂或耗时的任务。软中断是在内核中断上下文之外的一种执行机制。

代码实现:

1、Tasklet

void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)

tasklet_init 是 Linux 内核中用于初始化 Tasklet 结构体的函数。

  • t 是要初始化的 Tasklet 结构体指针。
  • func 是 Tasklet 的处理函数,即中断下半部的处理逻辑。
  • data 是传递给处理函数的参数。

static inline void tasklet_schedule(struct tasklet_struct *t)

tasklet_schedule 是 Linux 内核中用于调度 Tasklet 来执行任务的函数,在中断处理触发后合适的位置执行;

  • t 是要调度执行的 Tasklet 结构体指针。
void tasklet_kill(struct tasklet_struct *t);

tasklet_kill 是 Linux 内核中用于终止 Tasklet 的函数。

举个例子:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>#include <linux/interrupt.h>#define GPIO_BUTTON_PIN 40static unsigned int irq_num;struct tasklet_struct key_drv_tasklet;static void key_drv_tasklet_handler(unsigned long data) {printk("Tasklet executed in delayed context\n");
}// 中断处理函数
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{int value = gpio_get_value(GPIO_BUTTON_PIN);if (!value) {printk("====> key press\n");} else {printk("====> key up\n");}tasklet_schedule(&key_drv_tasklet);return IRQ_HANDLED;
}static int __init key_drv_init(void) {int ret;// 获取中断号// 请求 GPIO 引脚ret = gpio_request(GPIO_BUTTON_PIN, "button_gpio");if (ret) {printk(KERN_ERR "Failed to request GPIO pin\n");return ret;}// 设置 GPIO 引脚方向为输入ret = gpio_direction_input(GPIO_BUTTON_PIN);if (ret) {printk(KERN_ERR "Failed to set GPIO pin direction\n");gpio_free(GPIO_BUTTON_PIN);return ret;}// 将 GPIO 映射到 IRQirq_num = gpio_to_irq(GPIO_BUTTON_PIN);if (irq_num < 0) {printk(KERN_ERR "Failed to map GPIO to IRQ\n");gpio_free(GPIO_BUTTON_PIN);return irq_num;}tasklet_init(&key_drv_tasklet, key_drv_tasklet_handler, 0);// 请求中断ret = request_irq(irq_num, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq", NULL);if (ret) {printk(KERN_ERR "Failed to register IRQ handler\n");gpio_free(GPIO_BUTTON_PIN);return ret;}return 0;
}static void __exit key_drv_exit(void) {free_irq(irq_num, NULL);tasklet_kill(&key_drv_tasklet);gpio_free(GPIO_BUTTON_PIN);
}module_init(key_drv_init);
module_exit(key_drv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("dengcaixiang");
MODULE_DESCRIPTION("Simple key driver");

执行结果:

2、工作队列

INIT_WORK(work, func)

INIT_WORK 是 Linux 内核中用于初始化工作队列中的工作项的宏

  • work 是要初始化的 struct work_struct 结构体指针。
  • func 是要与工作项关联的处理函数的函数指针。
static inline bool schedule_work(struct work_struct *work)

schedule_work 用于将一个工作项(struct work_struct)添加到工作队列中以延迟执行。

  • work:指向要添加到工作队列中的工作项的指针,类型为 struct work_struct *。该工作项必须是预先初始化的,并且在调用 schedule_work() 函数之后,内核将负责安排该工作项的执行。

举个例子:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>#include <linux/workqueue.h>
#include <linux/interrupt.h>#define GPIO_BUTTON_PIN 40static unsigned int irq_num;static struct work_struct key_drv_workqueue;static void key_drv_work_handler(struct work_struct *work) {printk("Workqueue executed in process context\n");
}// 中断处理函数
static irqreturn_t key_irq_handler(int irq, void *dev_id)
{int value = gpio_get_value(GPIO_BUTTON_PIN);if (!value) {printk("====> key press\n");} else {printk("====> key up\n");}schedule_work(&key_drv_workqueue);return IRQ_HANDLED;
}static int __init key_drv_init(void) {int ret;// 获取中断号// 请求 GPIO 引脚ret = gpio_request(GPIO_BUTTON_PIN, "button_gpio");if (ret) {printk(KERN_ERR "Failed to request GPIO pin\n");return ret;}// 设置 GPIO 引脚方向为输入ret = gpio_direction_input(GPIO_BUTTON_PIN);if (ret) {printk(KERN_ERR "Failed to set GPIO pin direction\n");gpio_free(GPIO_BUTTON_PIN);return ret;}// 将 GPIO 映射到 IRQirq_num = gpio_to_irq(GPIO_BUTTON_PIN);if (irq_num < 0) {printk(KERN_ERR "Failed to map GPIO to IRQ\n");gpio_free(GPIO_BUTTON_PIN);return irq_num;}INIT_WORK(&key_drv_workqueue, key_drv_work_handler);// 请求中断ret = request_irq(irq_num, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq", NULL);if (ret) {printk(KERN_ERR "Failed to register IRQ handler\n");gpio_free(GPIO_BUTTON_PIN);return ret;}return 0;
}static void __exit key_drv_exit(void) {free_irq(irq_num, NULL);gpio_free(GPIO_BUTTON_PIN);
}module_init(key_drv_init);
module_exit(key_drv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("dengcaixiang");
MODULE_DESCRIPTION("Simple key driver");

执行结果:

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

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

相关文章

O2OA(翱途)移动端如何查看系统日志?

O2OA(翱途)移动端如何查看系统日志&#xff1f; 一、进入APP移动端应用&#xff0c;点击右下角“设置” 二、点击“系统日志”&#xff0c;如下图所示 点开日志列表即可查看。

关于 CTF 中 php 考点与绕过那些事的总结

关于 CTF 中常见 php 绕过的总结可以参考我之前的博客&#xff1a; CTF之PHP特性与绕过 PHP特性之CTF中常见的PHP绕过-CSDN博客 其中主要介绍了 md5()、sha1()、strcmp、switch、intval、$_SERVER 函数、三元运算符、strpos() 、数组、非法参数名传参等相关的绕过。 在此基础上…

Linux系统使用宝塔面板安装MySQL服务并实现公网远程访问本地数据库【内网穿透】

文章目录 前言1.Mysql服务安装2.创建数据库3.安装cpolar3.2 创建HTTP隧道 4.远程连接5.固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 宝塔面板的简易操作性,使得运维难度降低,简化了Linux命令行进行繁琐的配置,下面简单几步,通过宝塔面板cp…

在Java中处理JSON数据:Jackson与Gson库比较

引言 JSON&#xff0c;作为一种轻量级的数据交换格式&#xff0c;因其易于人阅读和编写&#xff0c;同时也易于机器解析和生成&#xff0c;而被广泛应用于网络通信和配置文件中。在Java中&#xff0c;有两个强大的工具帮助咱们处理JSON数据——Jackson和Gson。这两个库各有千秋…

从零开始写 Docker(四)---使用 pivotRoot 切换 rootfs 实现文件系统隔离

本文为从零开始写 Docker 系列第四篇&#xff0c;在mydocker run 基础上使用 pivotRoot 系统调用切换 rootfs 实现容器和宿主机之间的文件系统隔离。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识&…

javascript作用域编译浅析

作用域思维导图 1&#xff1a;编译原理 分词/词法分析 如果词法单元生成器在判断a是一个独立的词法单元还是其他词法单元的一部分时&#xff0c;调用的是有状态的解析规则&#xff0c;那么这个过程就被称为词法分析。 解析/语法分析 由词法单元流转换成一个由元素逐级嵌套所组…

期货开户交易软件如何下单?

一、手机和电脑使用的交易软件 目前期货市场常用的软件有文华、博弈、快期、易盛、同花顺等&#xff0c;这5款电脑软件对应的手机端是文华随身行、博弈手机版、快期小Q、易盛易星、同花顺期货通&#xff0c;这些常用软件大部分期货公司都是支持的。 二、交易软件如何下单 软…

C打印内存16进制

下面是一段C代码打印16进制 void print_hex(const char *msg, void *addr, int len) {uint8_t *p (uint8_t *)addr;printf("%s ,stat:%0x8, len:%d\n", msg, addr, len);for (int i 0; i < len / 16; i) {printf("0x%08x: ", p i * 16);for (int j …

【音视频开发好书推荐】《RTC程序设计:实时音视频权威指南》

1、WebRTC概述 WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个由Google发起的实时音视频通讯C开源库&#xff0c;其提供了音视频采集、编码、网络传输&#xff0c;解码显示等一整套音视频解决方案&#xff0c;我们可以通过该开源库快速地构建出一个音视频通…

【小黑嵌入式系统第十七课】结课总结(一)——硬件部分(系统总线处理器外设通信)

上一课&#xff1a; 【小黑嵌入式系统第十六课】PSoC 5LP第三个实验——μC/OS-III 综合实验 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能 文章目录 一、基础知识…

2024新版SonarQube+JenKins+Github联动代码扫描(1)-JenKins安装与配置

文章目录 前言一、官网下载二、访问ip:port三、安装推荐插件-自动下载四、创建用户名密码五、安装SonarQube插件六、配置全局工具总结 前言 Sonar是一个半开源的静态代码扫描工具&#xff0c;试用过一次觉得功能还算可以&#xff0c;所以记录一下SonarQube扫描的用法以及在中大…

IO接口 2月5日学习笔记

1.fgetc 用于从文件中读取一个字符&#xff0c;fgetc 函数每次调用将会返回当前文件指针所指向的字符&#xff0c;并将文件指针指向下一个字符。 int fgetc(FILE *stream); 功能: 从流中读取下一个字符 参数: stream:文件流指针 返回值: …

5分钟速成渐变色css

色彩的分支——渐变色定义&#xff1a;按照一定规律做阶段性变化的色彩&#xff08;抽象&#xff01;&#xff01;&#xff01;&#xff09; 我们可以将图片分为两块 以中心线为参考&#xff0c;再来看渐变色的定义&#xff1a;按照一定规律做阶段性变化的色彩 既然是按一定的…

使用Android Native Hook技术解决VLC播放器闪退的问题

文章目录 1.概述2.问题描述3.问题分析4.问题解决5.总结 1.概述 在做公司的一个TOB的需求时&#xff0c;发现调起Unity提供的3D播放器播放网络在线视频时闪退了&#xff0c;然后就拉着相关部门的人一起分析问题&#xff0c;最后定位到是VLC里面用到的系统日志打印函数在部分的系…

动态代理IP的并发处理技巧

目录 前言 一、什么是动态代理IP&#xff1f; 二、动态代理IP的并发处理技巧 1. 获取代理IP 2. 动态生成代理对象 3. 并发处理 总结 前言 在进行网络爬虫开发时&#xff0c;经常会遇到限制IP访问频率的情况。为了突破这个限制&#xff0c;我们可以通过使用代理IP来实现…

华为配置基于VLAN限速示例

华为配置基于VLAN限速示例 组网图形 图1 流量监管配置组网图 表1 Switch为上行流量提供的QoS保障 流量类型 CIR(kbps) PIR(kbps) DSCP优先级 语音 2000 10000 46 视频 4000 10000 30 数据 4000 10000 14 ^^^ 流分类简介配置注意事项组网需求配置思路操作步…

C#与欧姆龙PLC实现CIP通讯

参考文档&#xff1a; 欧姆龙PLC使用-CSDN博客 CIP通讯介绍&#xff08;欧姆龙PLC&#xff09;-CSDN博客 使用NuGet添加引用&#xff1a;CIPCompolet 基础参考我的CIP协议介绍&#xff0c;默认TCP端口为&#xff1a;44818 类NXCompolet 类的功能可以在安装PLC开发软件后帮…

vue svelte solid 虚拟滚动性能对比

前言 由于svelte solid 两大无虚拟DOM框架&#xff0c;由于其性能好&#xff0c;在前端越来越有影响力。 因此本次想要验证&#xff0c;这三个框架关于实现表格虚拟滚动的性能。 比较版本 vue3.4.21svelte4.2.12solid-js1.8.15 比较代码 这里使用了我的 stk-table-vue(np…

web坦克大战小游戏

H5小游戏源码、JS开发网页小游戏开源源码大合集。无需运行环境,解压后浏览器直接打开。有需要的订阅后,私信本人,发源码,含60+小游戏源码。如五子棋、象棋、植物大战僵尸、贪吃蛇、飞机大战、坦克大战、开心消消乐、扑鱼达人、扫雷、打地鼠、斗地主等等。 <!DOCTYPE htm…

【图论】Dijkstra 算法求最短路 - 构建邻接矩阵(带权无向图)

文章目录 例题&#xff1a;到达目的地的方案数题目描述代码与解题思路构建带权无向图的邻接矩阵 例题&#xff1a;到达目的地的方案数 题目链接&#xff1a;1976. 到达目的地的方案数 题目描述 代码与解题思路 func countPaths(n int, roads [][]int) int {g : make([][]int…