当前位置: 首页 > article >正文

驱动中阻塞相关函数的基础

wait_queue_head_t定义等待队列头#include linux/wait.h /* * lock自旋锁用于保护队列操作如添加/删除等待项的并发安全 * head链表头指向等待队列项的链表 */ typedef struct wait_queue_head { spinlock_t lock; struct list_head head; } wait_queue_head_t;1.2 init_waitqueue_head初始化一个已经分配了内存的等待队列头设置其自旋锁和链表为空void init_waitqueue_head(wait_queue_head_t *q);1.3 DECLARE_WAITQUEUE静态声明并初始化一个等待队列项wait queue entry。该宏创建一个 wait_queue_entry 类型的变量并将指定的进程描述符 tsk 当前进程为 current 与该队列项关联同时设置默认的唤醒函数DECLARE_WAITQUEUE(name, tsk); // 使用方式 DECLARE_WAITQUEUE(wait, current); // 展开后为 wait_queue_entry_t wait { .private current, // 指向等待的进程 task_struct .func default_wake_function, // 唤醒时调用的函数 .task_list { NULL, NULL } // 链表节点用于挂入等待队列头 };1.4 add_wait_queue将一个已经初始化好的等待队列项 wait 添加到等待队列头 queue 所管理的队列中。添加后该队列项就成为了等待队列的一部分在进程准备睡眠之前先将自己添加到等待队列这样其他唤醒者才能找到它void add_wait_queue(wait_queue_head_t *queue, wait_queue_t *wait);1.5 set_current_state设置当前进程的状态将 current-state 赋值为 new_state进程状态定义在 linux/sched.h 中常见的有TASK_RUNNING可运行状态正在运行或就绪。TASK_INTERRUPTIBLE可中断的睡眠状态可以被信号唤醒。TASK_UNINTERRUPTIBLE不可中断的睡眠状态只能由显式唤醒解除。void set_current_state(int new_state); // 有内存屏障保证顺序 void __set_current_state(int new_state); // 没有内存屏障1.6remove_wait_queue将之前通过 add_wait_queue 添加的等待队列项从等待队列中移除当进程被唤醒并重新获得 CPU 后通常需要调用此函数将自己从等待队列中删除表示不再等待该条件如果忘记移除队列项仍留在等待队列中可能导致后续不必要的唤醒或资源泄漏void remove_wait_queue(wait_queue_head_t *queue, wait_queue_t *wait);1.7wake_up唤醒队列中所有进程包括 TASK_UNINTERRUPTIBLE和 TASK_INTERRUPTIBLE void wake_up(wait_queue_head_t *queue);唤醒等待队列 queue 中所有状态为 TASK_INTERRUPTIBLE 的进程。这些进程将被设置为 TASK_RUNNING 并移入运行队列等待调度器选择它们运行void wake_up_interruptible(wait_queue_head_t *queue);2. 阻塞驱动使用例子#include linux/init.h #include linux/errno.h #include linux/mm.h #include linux/sched.h #include linux/module.h #include linux/ioctl.h #include linux/io.h #include linux/fs.h #include linux/cdev.h #include linux/uaccess.h #include linux/slab.h #include linux/wait.h #define GLOBALFIFO_SIZE 1024 #define GLOBALMEM_MAGIC M #define MEM_CLEAR _IO(GLOBALMEM_MAGIC, 0) struct globalfifo_dev { struct cdev m_cdev; /* 字符设备 */ unsigned int current_len; /* fifo有效数据长度 */ unsigned char mem[GLOBALFIFO_SIZE]; /* 全局内存 */ struct semaphore sem; /* 并发控制信号量 */ wait_queue_head_t r_wait; /* 阻塞读等待队列头 */ wait_queue_head_t w_wait; /* 阻塞写等待队列头 */ }; static int globalfifo_major 266; // 存放字符设备私有数据 struct globalfifo_dev* globalfifo_devp; /* user open fd */ static int globalfifo_open(struct inode* inode, struct file* filp) { struct globalfifo_dev* dev; dev container_of(inode-i_cdev, struct globalfifo_dev, m_cdev); filp-private_data dev; return 0; } /* user release fd*/ static int globalfifo_release(struct inode* inode, struct file* filp) { return 0; } /* user read fd */ static ssize_t globalfifo_read(struct file* filp, char __user* buf, size_t count, loff_t* ppos) { int ret; struct globalfifo_dev* dev filp-private_data; // 定义等待队列 DECLARE_WAITQUEUE(wait, current); down(dev-sem); // 1.将等待队列加入到等待队列头 add_wait_queue(dev-r_wait, wait); // 2.循环检查等待条件防止假唤醒如果唤醒后不满足条件会再次睡眠 while (dev-current_len 0) { // 3. 检查非阻塞模式直接返回 if (filp-f_flags O_NONBLOCK) { ret -EAGAIN; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } // 4.改变进程状态为可中断睡眠 __set_current_state(TASK_INTERRUPTIBLE); up(dev-sem); // 5.调度其他进程执行真正睡眠 schedule(); // 6.检查如果有信号到达返回上层处理错误自己的唤醒只将状态转换为TASK_RUNNING但信号到来也会做这个处理 if (signal_pending(current)) { ret -ERESTARTSYS; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } // 被唤醒后的处理 down(dev-sem); } if(count dev-current_len) count dev-current_len; if(copy_to_user(buf, dev-mem, count)) { ret -EFAULT; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } else { memcpy(dev-mem, dev-mem count, dev-current_len - count); dev-current_len - count; wake_up_interruptible(dev-w_wait); // 读出数据后唤醒写进程 ret count; } up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } /* user write fd */ static ssize_t globalfifo_write(struct file* filp, const char __user* buf, size_t count, loff_t* ppos) { int ret; struct globalfifo_dev* dev filp-private_data; // 定义等待队列 DECLARE_WAITQUEUE(wait, current); down(dev-sem); // 1.将等待队列插入写等待队列头 add_wait_queue(dev-w_wait, wait); // 2.循环等待 若FIFO满则应该挂起 while (dev-current_len GLOBALFIFO_SIZE) { // 3. 若非阻塞则直接返回 if (filp-f_flags O_NONBLOCK) { up(dev-sem); ret -EAGAIN; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } // 4.将进程状态改为可打断睡眠 __set_current_state(TASK_INTERRUPTIBLE); up(dev-sem); // 5.调度其他进程真正睡眠 schedule(); // 6.若因为信号唤醒则返回让上层完成错误处理 if (signal_pending(current)) { ret -ERESTARTSYS; remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } down(dev-sem); } if (count GLOBALFIFO_SIZE - dev-current_len) count GLOBALFIFO_SIZE - dev-current_len; if (copy_from_user(dev-mem, buf, count)) { ret -EFAULT; up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return ret; } else { dev-current_len count; // 唤醒等待队列 wake_up_interruptible(dev-r_wait); ret count; } up(dev-sem); remove_wait_queue(dev-w_wait, wait); set_current_state(TASK_RUNNING); return count; } /* user lseek fd */ static loff_t globalfifo_llseek(struct file* filp, loff_t offset, int orig) { loff_t ret; switch(orig) { // 从起始位置开始移动指针 case 0: if(offset 0) { ret -EINVAL; break; } if((unsigned int)offset GLOBALFIFO_SIZE) { ret -EINVAL; break; } filp-f_pos (unsigned int)offset; ret filp-f_pos; break; // 从当前位置开始移动指针 case 1: if((filp-f_pos offset) GLOBALFIFO_SIZE) { ret -EINVAL; break; } if((filp-f_pos offset) 0) { ret -EINVAL; break; } filp-f_pos offset; ret filp-f_pos; break; default: ret -EINVAL; } return ret; } /* user ioctl fd */ static long globalfifo_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ // 获取设备结构体指针 struct globalfifo_dev* dev filp-private_data; switch(cmd) { case MEM_CLEAR: down(dev-sem); dev-current_len 0; memset(dev-mem, 0, GLOBALFIFO_SIZE); up(dev-sem); break; default: return -EINVAL; } return 0; } static const struct file_operations globalfifo_fops { .owner THIS_MODULE, .open globalfifo_open, .release globalfifo_release, .llseek globalfifo_llseek, .read globalfifo_read, .write globalfifo_write, .unlocked_ioctl globalfifo_unlocked_ioctl }; /* 设备驱动模块insmod加载函数 */ static int globalfifo_init(void) { // 向 Linux 内核中注册字符设备编号范围 register_chrdev_region(MKDEV(globalfifo_major, 0), 1, globalfifo); // 为设备以及共享内存分配内存 globalfifo_devp kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL); memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev)); // 初始化字符设备0的基本字段 cdev_init(globalfifo_devp-m_cdev, globalfifo_fops); globalfifo_devp-m_cdev.owner THIS_MODULE; // 将主设备号globalfifo_major次设备号0与字符设备驱动的关联 cdev_add(globalfifo_devp-m_cdev, MKDEV(globalfifo_major, 0), 1); // 初始化信号量 sema_init(globalfifo_devp-sem, 1); // 初始化读写等待队列头 init_waitqueue_head(globalfifo_devp-r_wait); init_waitqueue_head(globalfifo_devp-w_wait); return 0; } static void globalfifo_exit(void) { dev_t devno; // 注销cdev cdev_del(globalfifo_devp-m_cdev); // 释放设备结构体内存 kfree(globalfifo_devp); // 释放设备号 devno MKDEV(globalfifo_major, 0); unregister_chrdev_region(devno, 1); } MODULE_AUTHOR(cear); MODULE_LICENSE(GPL); module_param(globalfifo_major, int, S_IRUGO); module_init(globalfifo_init); module_exit(globalfifo_exit);

相关文章:

驱动中阻塞相关函数的基础

wait_queue_head_t定义等待队列头#include <linux/wait.h> /** lock&#xff1a;自旋锁&#xff0c;用于保护队列操作&#xff08;如添加/删除等待项&#xff09;的并发安全* head&#xff1a;链表头&#xff0c;指向等待队列项的链表*/ typedef struct wait_queue_head …...

RISC-V开发工具链技术解析与选型指南

1. RISC-V开发工具链技术解析1.1 RISC-V生态发展背景随着处理器架构领域对开放性和灵活性的需求增长&#xff0c;RISC-V指令集架构凭借其开源特性获得了广泛关注。与传统架构相比&#xff0c;RISC-V免除了授权费用&#xff0c;降低了开发门槛&#xff0c;这使得芯片厂商和工具链…...

计算机毕业设计springboot鲜花在线商城 基于SpringBoot的园艺花卉网络销售系统 基于Java Web的线上花店订购管理平台

计算机毕业设计springboot鲜花在线商城911yt9 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09;本套源码可以先看具体功能演示视频领取&#xff0c;文末有联xi 可分享近年来&#xff0c;互联网技术的迅猛发展和智能终端设备的全面普及&#xff0c;为传统零售行业带来…...

重构窗口管理逻辑的效率革命:Loop重新定义macOS多任务体验

重构窗口管理逻辑的效率革命&#xff1a;Loop重新定义macOS多任务体验 【免费下载链接】Loop MacOS窗口管理 项目地址: https://gitcode.com/GitHub_Trending/lo/Loop 当你在三个浏览器窗口、两个文档和一个设计工具间频繁切换时&#xff0c;当你花费十分钟拖拽调整窗口…...

ExplorerPatcher:Windows资源管理器崩溃修复与体验增强的终极解决方案

ExplorerPatcher&#xff1a;Windows资源管理器崩溃修复与体验增强的终极解决方案 【免费下载链接】ExplorerPatcher 提升Windows操作系统下的工作环境 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher 你是否经历过Windows 11资源管理器频繁崩溃的困…...

三步掌握HiGHS线性优化求解器:从入门到实战

三步掌握HiGHS线性优化求解器&#xff1a;从入门到实战 【免费下载链接】HiGHS Linear optimization software 项目地址: https://gitcode.com/GitHub_Trending/hi/HiGHS 在数据分析与决策优化领域&#xff0c;如何高效解决资源分配、生产计划等线性规划问题一直是核心挑…...

BooruDatasetTagManager 2.5.0:重构AI训练数据标注的技术架构与效率范式

BooruDatasetTagManager 2.5.0&#xff1a;重构AI训练数据标注的技术架构与效率范式 【免费下载链接】BooruDatasetTagManager 项目地址: https://gitcode.com/gh_mirrors/bo/BooruDatasetTagManager 在计算机视觉和生成式AI模型训练的工作流中&#xff0c;数据标注的质…...

3分钟快速上手:用BepInEx为Unity游戏添加无限可能的终极插件框架

3分钟快速上手&#xff1a;用BepInEx为Unity游戏添加无限可能的终极插件框架 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx 你是否曾想过为心爱的Unity游戏添加新功能&#xff0c…...

OpenClaw怎么做到不串台、能并行、还总回对群 [特殊字符]✅(含源码解析)--OpenClaw系列第1期

你把 OpenClaw 部署进群&#xff0c;大家立刻把它当万能同事用&#xff1a;小王在 dev-team 群&#xff1a;bot 帮我写发布计划小李在同群线程&#xff1a;bot CI 为啥挂了&#xff1f;你在私聊&#xff1a;这个别在群里说…还有人&#xff1a;bot 同时分析文档 A、B&#xff0…...

Attention Unet vs Unet++:在Camvid数据集上的性能对比实验

Attention Unet与Unet在Camvid数据集上的深度性能评测 语义分割作为计算机视觉领域的核心任务之一&#xff0c;其模型架构的创新从未停止。在众多改进方案中&#xff0c;Attention机制与嵌套跳跃连接&#xff08;Nested Skip Connection&#xff09;分别代表了两种不同的优化思…...

Bedook超声波传感器应用测试

⒈实物和型号⑴产品型号&#xff1a;Bedook UM30-T20P-C31S12-X&#xff08;PNP型&#xff09;⑵实物图片&#xff1a;⑶产品规格&#xff1a;一般说明感应距离150…2000mm调节范围200…2000mm盲区0…150mm标准检测物100mm100mm换能器频率112kHz响应延时出厂设定200ms工作方式/…...

海康MVS安装注意事项

⒈目的 掌握海康MVS相机配置软件安装技巧&#xff0c;以便在MvCameraControlNet的演示案例运行时不报错&#xff08;通常为找不到MvCameraControl.dll&#xff09;&#xff0c;问题为MVS安装时无法对安装环境进行配置。 ⒉安装资源 在海康机器人官网上&#xff1a;海康机器人…...

Ai人工智能知识补充

文章目录 1.5 数据与算法基础:智能系统的“燃料”与“引擎” 1.5.1 数据工程:从原始数据到模型“燃料”的全链路 1.5.2 算法模型构建:从问题定义到模型部署的“炼金术” 1.5.3 数据隐私与安全:在价值挖掘与权利保护间走钢丝 1.6 面临的主要挑战:通往真正智能之路的险阻 1.…...

如何快速创建专业图表:Mermaid数据可视化的完整指南

如何快速创建专业图表&#xff1a;Mermaid数据可视化的完整指南 【免费下载链接】mermaid mermaid-js/mermaid: 是一个用于生成图表和流程图的 Markdown 渲染器&#xff0c;支持多种图表类型和丰富的样式。适合对 Markdown、图表和流程图以及想要使用 Markdown 绘制图表和流程图…...

如何使用设计模式-误区

通过学习设计模式&#xff0c;可以使软件开发人员的面向对象分析和设计的能力得到很大的拓展和加强&#xff0c;即使编程人员还没有直接使用设计模式&#xff0c;只要真正用心理解了设计模式&#xff0c;那么软件开发人员的设计水平也将得到很大的提高。当然&#xff0c;学习设…...

嵌入式Linux开发板CH340驱动安装避坑指南(附详细步骤图)

嵌入式Linux开发板CH340驱动安装全流程解析与疑难排错 第一次接触嵌入式Linux开发板时&#xff0c;最让人头疼的往往不是代码编写&#xff0c;而是最基础的开发环境搭建。作为连接电脑与开发板的重要桥梁&#xff0c;CH340串口驱动的安装质量直接决定了后续调试效率。许多初学者…...

OBS Studio架构深度解析:如何构建专业级直播系统的核心技术栈

OBS Studio架构深度解析&#xff1a;如何构建专业级直播系统的核心技术栈 【免费下载链接】obs-studio OBS Studio - 用于直播和屏幕录制的免费开源软件。 项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio OBS Studio作为开源直播录制软件的标杆&#xff…...

STM32F407定时器TIMER进阶:从PWM生成到输入捕获的实战应用

1. STM32F407定时器基础回顾与进阶方向 在开始深入探讨PWM生成和输入捕获之前&#xff0c;我们先快速回顾一下STM32F407定时器的基本特性。这款芯片内置了多达14个定时器&#xff0c;分为高级控制定时器、通用定时器和基本定时器三大类。其中通用定时器(TIM2-TIM5, TIM9-TIM14)…...

RWKV7-1.5B-g1a作品分享:多轮追问下保持主题聚焦的能力验证

RWKV7-1.5B-g1a作品分享&#xff1a;多轮追问下保持主题聚焦的能力验证 1. 模型简介与测试背景 rwkv7-1.5B-g1a是基于RWKV-7架构的多语言文本生成模型&#xff0c;特别适合基础问答、文案续写、简短总结和轻量中文对话场景。本次测试将重点验证该模型在多轮对话中保持主题聚焦…...

OpenClaw+GLM-4.7-Flash:个人博客自动更新系统搭建

OpenClawGLM-4.7-Flash&#xff1a;个人博客自动更新系统搭建 1. 为什么需要自动化博客维护 作为一个技术博主&#xff0c;我每周至少要花3-4小时在博客维护上&#xff1a;构思主题、撰写内容、调整格式、发布更新。最痛苦的不是写作本身&#xff0c;而是那些重复性的机械工作…...

PyTorch模型的TensorRT优化:原理与实践

PyTorch模型的TensorRT优化&#xff1a;原理与实践 1. 背景与意义 在深度学习模型部署过程中&#xff0c;推理速度是一个关键指标。TensorRT是NVIDIA开发的高性能深度学习推理优化库&#xff0c;它可以显著提高模型的推理速度&#xff0c;降低延迟。本文将深入探讨TensorRT的工…...

PyTorch分布式训练:原理与实践

PyTorch分布式训练&#xff1a;原理与实践 1. 背景与意义 随着深度学习模型的不断增大和数据集规模的持续增长&#xff0c;单GPU训练已经无法满足需求。分布式训练成为训练大型模型的必要手段&#xff0c;它可以显著缩短训练时间&#xff0c;提高模型性能。PyTorch提供了强大的…...

计算机视觉:从基础到深度学习应用

计算机视觉&#xff1a;从基础到深度学习应用 1. 背景与意义 计算机视觉&#xff08;Computer Vision&#xff0c;简称CV&#xff09;是人工智能领域的重要分支&#xff0c;旨在使计算机能够理解和处理图像信息。随着深度学习的发展&#xff0c;计算机视觉取得了突破性进展&…...

NcmpGui:解锁网易云音乐NCM格式的终极桌面解决方案

NcmpGui&#xff1a;解锁网易云音乐NCM格式的终极桌面解决方案 【免费下载链接】ncmppGui 一个使用C编写的转换ncm文件的GUI工具 项目地址: https://gitcode.com/gh_mirrors/nc/ncmppGui 你是否曾因网易云音乐的NCM格式文件无法在其他播放器上正常播放而感到困扰&#x…...

突破Navicat 14天限制:3步搞定Mac版试用期无限重置工具

突破Navicat 14天限制&#xff1a;3步搞定Mac版试用期无限重置工具 【免费下载链接】navicat_reset_mac navicat16 mac版无限重置试用期脚本 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 问题场景&#xff1a;当数据库工作遇到试用期壁垒 想象这样…...

MiroFish群体智能引擎部署与配置全指南

MiroFish群体智能引擎部署与配置全指南 【免费下载链接】MiroFish A Simple and Universal Swarm Intelligence Engine, Predicting Anything. 简洁通用的群体智能引擎&#xff0c;预测万物 项目地址: https://gitcode.com/GitHub_Trending/mi/MiroFish MiroFish作为简洁…...

重新定义Windows桌面体验:Seelen UI如何让你告别千篇一律的界面

重新定义Windows桌面体验&#xff1a;Seelen UI如何让你告别千篇一律的界面 【免费下载链接】Seelen-UI The Fully Customizable Desktop Environment for Windows 10/11. 项目地址: https://gitcode.com/GitHub_Trending/se/Seelen-UI 厌倦了Windows千篇一律的桌面环境…...

终极游戏画质优化指南:3步让所有显卡享受DLSS级性能提升

终极游戏画质优化指南&#xff1a;3步让所有显卡享受DLSS级性能提升 【免费下载链接】OptiScaler DLSS replacement for AMD/Intel/Nvidia cards with multiple upscalers (XeSS/FSR2/DLSS) 项目地址: https://gitcode.com/GitHub_Trending/op/OptiScaler 还在为显卡性能…...

机器人状态估计——从IMU运动方程到ESKF误差状态建模(上)

1. 从IMU数据到机器人状态估计的挑战 当你第一次拿到一个IMU传感器时&#xff0c;可能会觉得它就像个魔法黑盒——只要把它装在机器人上&#xff0c;就能知道机器人的姿态、速度和位置。但实际操作起来&#xff0c;你会发现IMU数据就像个调皮的孩子&#xff0c;稍不注意就会给你…...

手把手教你修复conda的HTTP 404错误:从错误日志分析到快速解决

深度解析Conda的HTTP 404错误&#xff1a;从日志分析到高效修复 当你满怀期待地输入conda create -n myenv python3.9准备创建新环境时&#xff0c;终端却无情地抛出一堆红色错误信息&#xff0c;最扎眼的就是那个requests.exceptions.HTTPError: 404 Client Error。这种突如其…...