技术知识库

使用等待队列实现阻塞 KFIFO 邮箱

使用等待队列实现阻塞 KFIFO 邮箱

摘要

本实验在 misc + KFIFO 邮箱中加入读写等待队列。FIFO 为空时,普通 read() 通过 wait_event_interruptible() 等待写者;FIFO 为满时,普通 write() 等待读者释放空间。ARM64 模块已经运行验证:cat /dev/blockkfifo_mailbox 会等待,写入后被唤醒并读出数据。

原理见 等待队列如何实现字符设备阻塞读写。

目标与完成标准

  • 初始化独立的读等待队列和写等待队列。
  • 空 FIFO 的普通读取进入等待。
  • 写入数据后唤醒读者。
  • 读取数据后唤醒可能等待的写者。
  • 保留 O_NONBLOCK 下的 -EAGAIN 语义。
  • 在 ARM64 Debian 目标系统观察到等待与唤醒闭环。

环境与工作目录

主机:Ubuntu 26.04 x86-64
内核源码:/home/martin-zou/workspace/runninglinuxkernel_5.0
内核构建目录:build/arm64
目标系统:Linux 5.0.0+ ARM64,Debian 12,QEMU virt
工作目录:/home/martin-zou/workspace/gcc-lab/char_mod/blockkfifo_mailbox

完整实验源文件:

/home/martin-zou/workspace/gcc-lab/char_mod/blockkfifo_mailbox/blockkfifo_mailbox.c
/home/martin-zou/workspace/gcc-lab/char_mod/blockkfifo_mailbox/Makefile

核心设备状态

struct kfifo_device {
	const char *name;
	struct device *mymailbox_device;
	struct miscdevice *misc_mailbox_device;
	wait_queue_head_t read_queue;
	wait_queue_head_t write_queue;
};

DEFINE_KFIFO(misc_kfifo, char, 256);

模块初始化时执行:

init_waitqueue_head(&mykfifo_device.read_queue);
init_waitqueue_head(&mykfifo_device.write_queue);

阻塞读写关键路径

读取等待:

if (kfifo_is_empty(&misc_kfifo) &&
    (file->f_flags & O_NONBLOCK))
	return -EAGAIN;

ret = wait_event_interruptible(mykfifo_device.read_queue,
		!kfifo_is_empty(&misc_kfifo));

写入后唤醒读者:

if (!kfifo_is_empty(&misc_kfifo))
	wake_up_interruptible(&mykfifo_device.read_queue);

写入等待和读取后的唤醒采用对称逻辑,条件分别是“FIFO 非满”和 write_queue。

手动编译和部署

在主机执行:

cd /home/martin-zou/workspace/gcc-lab/char_mod/blockkfifo_mailbox
make clean
make
file blockkfifo_mailbox.ko
scp -P 2222 blockkfifo_mailbox.ko martin@127.0.0.1:~/

在目标系统执行:

sudo insmod ~/blockkfifo_mailbox.ko
ls -l /dev/blockkfifo_mailbox

验证阻塞和唤醒

终端 A:

cat /dev/blockkfifo_mailbox

FIFO 为空时命令保持等待。终端 B:

echo "dasdasd" > /dev/blockkfifo_mailbox

终端 A 随后输出:

dasdasd

这证明写者改变 FIFO 条件并唤醒了等待在同一设备 read_queue 上的读者。

完成标准

已完成实验 6-6 的核心闭环。当前笔记保留为 growing,后续补充信号中断等待和并发访问保护。

关联