技术知识库
每次 open 分配独立状态导致写者无法唤醒读者
每次 open 分配独立状态导致写者无法唤醒读者
摘要
实验 6-8 故意把 KFIFO 和等待队列放入每次 open() 新分配的私有对象。cat 和 echo 分别打开设备,得到两个不同对象;读者睡在队列 A,写者却写入 FIFO B、唤醒队列 B,因此读者无法继续。当前已经完成源码层面的根因回答,尚未在目标系统故意复现挂起现象。
环境
参考目录:kmodules/rlk_lab/rlk_basic/chapter_6_device_driver/lab8_mydemodrv_find_error
参考源码:mydemodrv_error.c
内核:Running Linux Kernel 5.0 ARM64
故意错误的状态归属
struct mydemo_private_data {
struct mydemo_device *device;
char name[64];
struct kfifo mydemo_fifo;
wait_queue_head_t read_queue;
wait_queue_head_t write_queue;
};
每次 open() 都执行 kmalloc()、kfifo_alloc() 和等待队列初始化:
cat open → private A → fifo A、read_queue A
echo open → private B → fifo B、read_queue B
根因
wake_up_interruptible() 只唤醒调用时传入的那一个等待队列。内核不会根据设备节点名称推断队列 A 和队列 B 应当属于同一个业务设备。
因此:
cat: wait_event_interruptible(read_queue A, fifo A 非空)
echo: kfifo_from_user(fifo B)
wake_up_interruptible(read_queue B)
写者确实执行了唤醒,但唤醒了错误的对象。
正确设计方向
每次打开可以继续拥有独立的 struct file 和少量私有上下文,但 KFIFO 与等待队列应放在模块初始化期间创建的共享 struct mydemo_device 中。两个打开者的 private_data 最终都引用同一个设备对象。
结论
此前给出的“生产者和消费者必须指向同一个共享设备状态”结论正确。更精确地说,决定条件是对象身份和指针关系,而不是内存连续性或注册代码是否写在一起。
关联
待验证
- 在目标系统运行故意错误版本,记录读者睡眠、写者唤醒另一队列的地址与 PID。