技术知识库
使用等待队列实现阻塞 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,后续补充信号中断等待和并发访问保护。