Skip to content

fix(pipe): 修复阻塞模式下写端唤醒的竞态条件#1529

Merged
fslongjin merged 1 commit intoDragonOS-Community:masterfrom
fslongjin:fix-pipe-writer-race-condition
Dec 21, 2025
Merged

fix(pipe): 修复阻塞模式下写端唤醒的竞态条件#1529
fslongjin merged 1 commit intoDragonOS-Community:masterfrom
fslongjin:fix-pipe-writer-race-condition

Conversation

@fslongjin
Copy link
Member

@fslongjin fslongjin commented Dec 21, 2025

  • 在阻塞模式下先增加 writer 计数再等待读端,避免竞态条件
  • 在增加 writer 计数后立即唤醒等待的读者
  • 处理信号中断时回滚 writer 计数
  • 确保非阻塞模式下也正确唤醒读者

问题现象

在 DragonOS 中,FifoTest.FifoTruncNoOp 测试用例多次运行时可能会出现卡死现象。该测试用例涉及 FIFO(命名管道)的创建和打开操作。

测试用例关键流程

测试用例 fifo.cc 的执行流程:

  1. 创建一个 FIFO 文件
  2. 启动一个读线程,以 O_RDONLY 模式打开 FIFO(会阻塞直到有写端打开)
  3. 主线程以 O_WRONLY | O_TRUNC 模式打开 FIFO(会阻塞直到有读端打开)
  4. 两个打开操作需要相互等待对方,存在潜在的竞态条件

死锁时序分析

时间 写线程 (O_WRONLY) 读线程 (O_RDONLY) 说明
T1 获取锁, 检查 reader==0 写线程检查无读端
T2 释放锁
T3 获取锁, reader=1, 释放锁 读线程增加 reader
T4 wakeup_all() 读线程唤醒等待的写端
T5 has_reader==false (旧值) 写线程使用旧值判断
T6 进入等待队列 写线程开始等待
T7 检查 writer==0 读端还未看到 writer
T8 进入等待队列 读线程也开始等待
结果 等待读端 等待写端 死锁!

问题根源

这是一个典型的 TOCTOU (Time-of-check to time-of-use) 竞态条件:

  1. 检查与更新分离:先检查 has_reader,后增加 writer 计数
  2. 状态更新顺序错误:应该在检查前增加计数,避免竞态窗口
  3. 唤醒时机问题:写端的 writer 计数增加太晚,导致读端检查时看不到写端存在

修复后的正确时序

时间 写线程 (O_WRONLY) 读线程 (O_RDONLY) 说明
T1 writer=1, 释放锁 写线程先增加计数
T2 wakeup_all() 立即唤醒等待的读端
T3 获取锁, reader=1, 释放锁
T4 检查 writer==1 ✓ 读端看到写端存在
T5 不进入等待,正常返回
T6 检查 has_reader (重新获取锁)
T7 检查 reader==1 ✓ 写端看到读端存在
T8 不进入等待,正常返回
结果 ✅ 成功 ✅ 成功 无死锁

关键修复点总结

  1. 调整操作顺序:将 writer += 1 移到等待之前
  2. 立即唤醒:增加计数后立即唤醒等待的读端
  3. 异常处理:被信号中断时回滚 writer 计数
  4. 保持非阻塞语义:非阻塞模式的逻辑保持不变

- 在阻塞模式下先增加 writer 计数再等待读端,避免竞态条件
- 在增加 writer 计数后立即唤醒等待的读者
- 处理信号中断时回滚 writer 计数
- 确保非阻塞模式下也正确唤醒读者

Signed-off-by: longjin <longjin@DragonOS.org>
@github-actions github-actions bot added Bug fix A bug is fixed in this pull request test Unitest/User space test labels Dec 21, 2025
@fslongjin fslongjin merged commit e7fa64b into DragonOS-Community:master Dec 21, 2025
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix A bug is fixed in this pull request test Unitest/User space test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant