Linux驱动中阻塞IO进程的处理机制
在面对驱动程序无法立即满足请求的情况下,我们需要考虑如何进行响应。通常情况下,调用进程并不会关心驱动程序的状态,所以我们需要在驱动程序中进行相应的处理。一种常见的做法是阻塞该进程的请求。
阻塞I/O是指在执行设备操作时,如果无法获得所需的资源,就会挂起当前进程,直到满足可操作的条件后再执行操作。被挂起的进程进入睡眠状态,并从调度器的运行队列中被移除,直到等待的条件满足。相反,非阻塞I/O在无法进行设备操作时,不会挂起进程,而是选择放弃或者持续轮询,直到可以进行操作为止。
“
等待队列是处理阻塞I/O的经典机制。
”
1. 驱动中阻塞I/O处理流程
概况来讲,阻塞I/O的处理流程包括4部分内容。首先初始化等待队列链表,该链表中存放需要阻塞的进程。然后初始化一个等待队列,并将当前需要阻塞的进程加入到等待队列链表中。再通过设置进程可中断状并将阻塞进程睡眠。最后,当某些条件满足亦即资源可用时,唤醒等待队列中的进程。
下图描述了阻塞I/O的处理流程:

2. 初始化等待队列链表
在进行初始化等待队列链表之前,我们首先需要定义一个wait_queue_head_t
的变量。例如在RK3399
的ISP驱动中数据结构struct rkisp1_stream
包含了wait_queue_head_t done;
。通过调用调用init_waitqueue_head(&stream->done);
进行初始化操作。
void rkisp1_stream_init(struct rkisp1_device *dev, u32 id) { struct rkisp1_stream *stream = &dev->stream[id]; memset(stream, 0, sizeof(*stream)); stream->id = id; stream->ispdev = dev; INIT_LIST_HEAD(&stream->buf_queue); init_waitqueue_head(&stream->done); spin_lock_init(&stream->vbq_lock); ... }
wait_queue_head_t
变量的原型是__wait_queue_head
,如下所示:
struct __wait_queue_head { spinlock_t lock; struct list_head task_list; };
init_waitqueue_head()
真正执行的函数是__init_waitqueue_head()
,它的函数定义如下:
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key) { spin_lock_init(&q->lock); lockdep_set_class_and_name(&q->lock, key, name); INIT_LIST_HEAD(&q->task_list); }
3. 等待队列处理
调用DECLARE_WAITQUEUE(wait, current)
将当前进程初始化为等待队列。注意,这里的等待队列和等待队列链表头可不是一个东东。
#define DECLARE_WAITQUEUE(name, tsk) \ wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
等待队列的定义如下:
struct __wait_queue { unsigned int flags; void *private; wait_queue_func_t func; struct list_head task_list; };
等待队列和等待队列链表头是通过add_wait_queue()
结合到一起的。
init_waitqueue_head(&delay_wait); add_wait_queue(&delay_wait, &wait);
以上代码是将等待队列进程加入到等待队列链表中:
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { list_add(&new->task_list, &head->task_list); }
4. 阻塞进程处理
阻塞进程处理包括两部分内容,首先设置进程的睡眠状态,包括TASK_INTERRUPTIBLE
和TASK_UNINTERRUPTIBLE
两种。前者用于可中断睡眠,后者用于不可中断睡眠。然后,将当前进程退出调度器让出CPU的使用权。
set_current_state(TASK_INTERRUPTIBLE); schedule();
5. 唤醒处理
唤醒处理通常位于中断处理函数或某些动作成功执行之后,特定条件满足时,唤醒通过阻塞队列睡眠的进程。例如:
void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int success, int behind) { if (!bitmap) return; if (behind) { if (atomic_dec_and_test(&bitmap->behind_writes)) wake_up(&bitmap->behind_wait); pr_debug("dec write-behind count %d/%lu\n", atomic_read(&bitmap->behind_writes), bitmap->mddev->bitmap_info.max_write_behind); } ... }
以上是Linux驱动中阻塞IO进程的处理机制的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Linux系统的五个基本组件是:1.内核,2.系统库,3.系统实用程序,4.图形用户界面,5.应用程序。内核管理硬件资源,系统库提供预编译函数,系统实用程序用于系统管理,GUI提供可视化交互,应用程序利用这些组件实现功能。

要查看 Git 仓库地址,请执行以下步骤:1. 打开命令行并导航到仓库目录;2. 运行 "git remote -v" 命令;3. 查看输出中的仓库名称及其相应的地址。

Linux的主要用途包括:1.服务器操作系统,2.嵌入式系统,3.桌面操作系统,4.开发和测试环境。Linux在这些领域表现出色,提供了稳定性、安全性和高效的开发工具。

虽然 Notepad 无法直接运行 Java 代码,但可以通过借助其他工具实现:使用命令行编译器 (javac) 编译代码,生成字节码文件 (filename.class)。使用 Java 解释器 (java) 解释字节码,执行代码并输出结果。

在 Sublime 中运行代码的方法有六种:通过热键、菜单、构建系统、命令行、设置默认构建系统和自定义构建命令,并可通过右键单击项目/文件运行单个文件/项目,构建系统可用性取决于 Sublime Text 的安装情况。

要安装 Laravel,需依序进行以下步骤:安装 Composer(适用于 macOS/Linux 和 Windows)安装 Laravel 安装器创建新项目启动服务访问应用程序(网址:http://127.0.0.1:8000)设置数据库连接(如果需要)

Visual Studio Code (VSCode) 是一款跨平台、开源且免费的代码编辑器,由微软开发。它以轻量、可扩展性和对众多编程语言的支持而著称。要安装 VSCode,请访问官方网站下载并运行安装程序。使用 VSCode 时,可以创建新项目、编辑代码、调试代码、导航项目、扩展 VSCode 和管理设置。VSCode 适用于 Windows、macOS 和 Linux,支持多种编程语言,并通过 Marketplace 提供各种扩展。它的优势包括轻量、可扩展性、广泛的语言支持、丰富的功能和版
