Perfetto中认识sleep的几个状态
最普通的sleep

State为Uninterruptible Sleep(non io)

State为Uninterruptible Sleep

D 状态 vs S 状态的差别
**S 状态(Interruptible Sleep)**可以被信号唤醒/打断;
**D 状态(Uninterruptible Sleep)**不能被任何信号打断,包括SIGKILL。
二者区别:

为什么要有 D 状态
主要是为了保证数据完整性和文件系统一致性:
- 在写磁盘时如果被 kill -9 打断,可能导致写了一半的脏数据留在内存中、文件系统元数据不一致
- 在持有内核 mutex/spinlock 等关键锁时,必须等待操作完成并释放锁,否则整个系统可能死锁
- 本质上是一种保护机制:宁可单个进程挂死,也不让内核状态被破坏
与 stop、zombie 的区别
R- 正在运行或在运行队列上
S- 可中断睡眠 (Interruptible Sleep)
D- 不可中断睡眠 (Uninterruptible Sleep)
T- 被 SIGSTOP/TSTP 暂停 (stopped by job control)
Z- 僵尸 (zombie, 已退出但父进程未 wait)
D 状态non-IO和IO是啥意思?
先剖析Uninterruptible Sleep(non io)中的block方法__fdget_pos

源码中查看__fdget_pos 为什么是 non-IO
// fs/file.c:832
mutex_lock(&file->f_pos_lock);// → schedule() ,不是 io_schedule()
//in_iowait = 0 → non-IO
它卡在 mutex 竞争上,不是在等磁盘 I/O 完成。等的是一个锁,不是一块数据从硬盘读上来。
mutex_lock() 内部调用 __mutex_lock_common(),使用的是 TASK_UNINTERRUPTIBLE。原因是:f_pos_lock 这个 mutex 保护的只是文件位置 (f_pos) 的一致性,虽然它本身不会直接涉及磁盘
I/O,但它的锁持有者(另一个线程)正在持有它做 I/O 操作。如果用 mutex_lock_interruptible(),被信号打断后需要处理回滚逻辑,而 VFS 层选择简单处理——宁可让等待者进 D 状态。
这是内核在 D 状态内部的一个细分,区分标志位是 task_struct->in_iowait。
核心区别
mutex_lock() → schedule()→ in_iowait = 0 → D (non-IO)
read() → vfs_read() → ... → io_schedule()→ in_iowait = 1 → D (IO)
- IO D 状态:通过 io_schedule() 进入睡眠,设置了 current->in_iowait = 1,表明线程在等磁盘/存储设备完成 I/O,CPU 本可以干别的活,这段时间被计入 iowait%
- non-IO D 状态:通过普通的 schedule() 睡眠(如 mutex_lock),in_iowait = 0,表明线程在等内核同步对象(锁、waitqueue),不计入 iowait%
内核源码中:
// kernel/sched/core.c:5328
long __sched io_schedule_timeout(long timeout)
{
int old_iowait = current->in_iowait;
current->in_iowait = 1; // ← 标记为 IO 等
...
schedule_timeout(timeout);
...
current->in_iowait = old_iowait;
}
只有调用 io_schedule() / io_schedule_timeout() 的路径才会标记为 IO wait。
实际意义

你看到的 D (non-IO) 意味着线程既杀不掉,也不会在 iowait 指标上体现出来——它在纯粹地等另一个线程释放 f_pos_lock 这个 mutex。
总结三个状态的场景
一、D (IO) — 不可中断 I/O 等待
内核路径:io_schedule() → in_iowait = 1
触发条件是同步等待磁盘/存储完成读写。
经典场景:
FileInputStream.read()------------- read() → io_schedule()
FileOutputStream.write() -------------write() → io_schedule()
二、D (non-IO) — 不可中断非 I/O 等待
内核路径:mutex_lock() / wait_event() → schedule() → in_iowait = 0
本质是等内核同步对象(mutex、waitqueue for non-IO condition)。
经典场景:
多个线程操作同一个 FileInputStream / RandomAccessFile ---- __fdget_pos() → mutex_lock(f_pos_lock)
三、S — 可中断睡眠
内核路径:wait_event_interruptible() / schedule_timeout() / futex → TASK_INTERRUPTIBLE
绝大多数日常操作都属于 S 状态。
经典场景:
Looper.loop()---- epoll_wait() — 等待输入事件
Thread.sleep() -----nanosleep()
**S 状态(Interruptible Sleep)**可以被信号唤醒/打断;
**D 状态(Uninterruptible Sleep)**不能被任何信号打断,包括SIGKILL。
原文地址:
https://mp.weixin.qq.com/s/dowcSg_HVVSMvNSHqXkgoA
790

被折叠的 条评论
为什么被折叠?



