Linux应用层程序中调用sleep函数
使用strace跟踪如下:
strace sleep_test(该main程序中进行sleep(10)调用)
nanosleep({tv_sec=10, tv_nsec=0}, 0x7fec466ca0) = 0
write(1, "sleep test", 10sleep test) = 10
write(1, "\n", 1
nanosleep最终会陷入到内核/kernel/time/hrtimer.c中
nanosleep
---hrtimer_nanosleep
---hrtimer_init_sleeper_on_stack
---do_nanosleep
---hrtimer_init_sleeper
---freezable_schedule
----__set_current_state(TASK_RUNNING)
do_nanosleep函数是睡眠的核心实现:首先设置任务的状态为可中断的睡眠状态,然后开启了之前设置的高精度定时器,随即调用freezable_schedule进行真正的睡眠
可以看到最终调用主调度器__schedule进行主动调度。
当任务睡眠完成,定时器超时,会调用之前hrtimer_init_sleeper设置的超时回调函数hrtimer_wakeup将睡眠的任务唤醒。hrtimer_wakeup函数如下:

freezable_schedule
->schedule()
->__schedule(false); 在kernel/sched/core.c中
处于用户态的任务,如果想要睡眠一段时间必须向内核请求服务(如调用nanosleep系统调用),内核中会设置一个高精度定时器,然后设置任务状态为可中断的睡眠状态,紧接着发生主动调度,这样任务就发生睡眠。
linux内核msleep函数
函数定义在kernel/time/timer.c中:

schedule_timeout_uninterruptible中这里可以看到,首先设置为不可中断状态__set_current_state(TASK_UNINTERRUPTIBLE); //设置任务状态为不可中断睡眠,然后记录定时器到期要唤醒的任务并通过schedule主动调度。

msleep不能用于中断上下文,因为中断函数不能休眠。
msleep实现睡眠是通过定时器,首先设置当前任务状态为不可中断睡眠,然后设置定时器超时时间为传递的ms级延迟转换的jiffies,超时回调函数为process_timeout,然后将定时器添加到系统中,最后调用schedule发起主动调度,当定时器超时的时候调用process_timeout来唤醒睡眠的任务。有关process_timeout是使用try_to_wake_up函数如何唤醒一个进程,有待后续继续研究。
类似msleep可中断的函数为msleep_interruptible,调用时可以被信号唤醒,并返回初始请求睡眠周期中剩余的毫秒数,;一般用于等待队列并需要打断休眠唤醒进程时。
/**
* msleep_interruptible - sleep waiting for signals
* @msecs: Time in milliseconds to sleep for
*/
unsigned long msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout);
return jiffies_to_msecs(timeout);
}
文章详细解析了Linux应用层程序如何通过nanosleep和msleep函数进行睡眠,以及这两个函数在内核中的实现过程。nanosleep涉及高精度定时器和主动调度,而msleep则设置任务为不可中断睡眠状态,并通过定时器超时唤醒。同时,文章指出msleep_interruptible允许被信号中断。
549

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



