背景
msleep 函数的核心逻辑是将毫秒数转换为内核的 jiffies 单位,并通过 schedule_timeout_uninterruptible 让当前进程进入不可中断的睡眠状态。
细节
/**
* msleep - sleep safely even with waitqueue interruptions
* @msecs: Time in milliseconds to sleep for
*/
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
可以看到将等待的毫秒换算为jiffies 然后 + 1,这里+1 是一个工程约等于。为了确保睡眠时间不会少于指定的毫秒数。msecs_to_jiffies 函数将毫秒转换为 jiffies,但由于 jiffies 是一个离散的计时单位,可能会导致精度损失。也体现了msleep精度并不是准确的毫秒。
另外可以看到msleep使用了while循环,但是会让出调度器。所以msleep会阻塞在这里。然后调度器每次调度回来msleep所在的执行单元后,会判断timeout是否已经timeout。进程会持续以不可中断的方式睡眠,直到timeout超时或者被其他机制唤醒。并且每次唤醒后会更新timeout的值。
其中schedule_timeout_uninterruptible在给定的超时时间内让当前进程进入睡眠状态,并且在睡眠期间不会被信号中断。睡眠期间,进程不会响应信号,但可以被内核的定时器机制或其他内核机制唤醒。如果超时时间到达,进程会被内核调度器唤醒。
这里所谓的不可中断为什么又能被其他机制唤醒呢?
这里涉及到Linux 内核的调度机制和信号处理机制。
“不可中断”(TASK_UNINTERRUPTIBLE)状态主体是进程。调用msleep的进程不会被信号(如 SIGINT(比如ctrl + c中断)、SIGTERM 等)唤醒。当进程处于这种状态时,它不会响应用户空间的信号中断,必须等到它自己完成睡眠或者被其他机制唤醒。
这里的中断不是只芯片的中断,不是一个概念和层次,他是一个进程能否被“叫停”。
内核驱动例子
static int wait_fw_init(struct mlx5_core_dev *dev, u32 max_wait_mili,
u32 warn_time_mili)
{
unsigned long warn = jiffies + msecs_to_jiffies(warn_time_mili);
unsigned long end = jiffies + msecs_to_jiffies(max_wait_mili);</
Linux内核msleep实现硬件状态间歇性确认

最低0.47元/天 解锁文章
1228

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



