linux kernel中的延时(二)

本文详细介绍了Linux设备驱动中两种主要的延时等待技术:忙等待和休眠等待。忙等待包括mdelay和使用time_before接口实现的延时,虽然精度高但消耗CPU资源。休眠等待如usleep_range、msleep和wait_event_interruptible_timeout则在减少CPU占用的同时可能精度稍逊。文章通过实例展示了各种延时函数的使用和效果,并提供了源代码供参考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概览

  在设备驱动中,有时候在驱动中延迟执行一些指令以等待硬件完成。延时一般分为两大类,第一类为忙等待即CPU在此期间执行的指令目的地仅仅是为了消耗时间。第二类为休眠等待唤醒,即在延时点进入休眠,然后被唤醒,这也就实现了驱动的等待功能。

2.CPU忙等待延时

2.1 mdelay

  代码过于简单,下面则是示例代码

time_test_drv_init
    DELAY_TEST_INFO("start:%lld ns", ktime_get_boottime_ns());
    mdelay(1000);
    DELAY_TEST_INFO("after mdelay:%lld ns", ktime_get_boottime_ns());

  执行结果如下

[  121.908834] delayTest:delay_test_drv_init,27:start:121905834566 ns
[  122.931042] delayTest:delay_test_drv_init,33:after mdelay:122928044142 ns

2.2 使用 time_before 接口实现忙等待

  使用之前提到过的接口 time_before 再配合循环也是可以实现忙等待的,示例代码如下

unsigned long delayTime = jiffies + HZ;//delay 1s
while(time_before(jiffies, delayTime));

  实现的逻辑很简单,在每一个循环中都判断下当前时间是否超期预设值(delayTime),如果超期了那么就不成立退出循环了。
  使用这类的等待实际上非常浪费CPU的,所以尽量能不使用则不使用吧。

3.休眠等待延时

  这一类的等待在精度上是不如忙等待的,因为这需要一个休眠唤醒的过程,但对CPU的消耗则会小的多。不过对于这类接口是不能在原子和中断上下文中调用的,在使用这些接口时一定要确认当前所在的上下文。

3.1 usleep_range

  使用该接口来设置延时,内核会根据所设置的范围来决定能否复用已有的唤醒中断,因此相较于usleep这样更加节省系统资源。下面是使用示例

usleep_range(1000000,1500000);
DELAY_TEST_INFO("after usleep_range:%lld ns", ktime_get_boottime_ns());

  usleep_range的入参单位都是微妙,所以在示例代码中设置了本次延时可以接收的范围是1s~1.5s。
  下面是执行结果

[  122.931042] delayTest:delay_test_drv_init,33:after mdelay:122928044142 ns
[  124.256229] delayTest:delay_test_drv_init,38:after usleep_range:124253207756 ns

  124253207756 - 122928044142 = 1,325,163,614ns,可见还是满足期望值的。

3.2 msleep

  调用该接口后会在设置的毫秒之后被唤醒,但是接口msleep_interruptible则是可以被消耗所打断的,例如在调用msleep_interruptible进入休眠后,有信号发送到当前进入休眠等待的进程,那么该进程也会被唤醒,那么此时的休眠时间就不够所设了,下面时示例代码

msleep(1000);//http://lkml.org/lkml/2007/8/3/250
DELAY_TEST_INFO("after msleep:%lld ns", ktime_get_boottime_ns());
msleep_interruptible(1000);
DELAY_TEST_INFO("after msleep_interruptible:%lld ns", ktime_get_boottime_ns());

  如下则为执行结果

[  124.256229] delayTest:delay_test_drv_init,38:after usleep_range:124253207756 ns
[  125.280232] delayTest:delay_test_drv_init,40:after msleep:125277210986 ns
[  126.303898] delayTest:delay_test_drv_init,42:after msleep_interruptible:126300866101 ns

3.5 wait_event_interruptible_timeout

  这种延迟的实现是有点取巧的,但是好处就是延迟时间单位可以和jiffies的精度一致。本接口只要满足下面的任意一种条件则会返回,
   a)条件为真时
   c)当timeout时间用完时
  所以这里将条件设置为0,那么也就实现了延时的功能,下面是示例代码

struct wait_queue_head wait_head;
init_waitqueue_head(&wait_head);
wait_event_timeout(wait_head, 0 , HZ);//1s delay
DELAY_TEST_INFO("after wait_event_timeout:%lld ns", ktime_get_boottime_ns());

  执行结果如下

[  341.376510] delayTest:delay_test_drv_init,52:after msleep_interruptible:341373267986 ns new
[  342.400526] delayTest:delay_test_drv_init,59:after wait_event_timeout:342397288024 ns

4.源码如下

delayTest

https://gitee.com/solo-king/linux-kernel-base-usage/blob/master/flagstaff/delayTest.c
### Linux延迟内核配置与使用 #### 配置选项 对于Linux延迟内核而言,其主要目标在于减少系统的响应时间以及提高实时性能。为此,在编译内核时可以选择一系列专门针对此目的设计的参数设置。例如`CONFIG_PREEMPT_RT`就是用来启用完全抢占式的实时补丁集[^1]。 当涉及到具体的应用场景时,像音频处理、视频流传输等领域往往对延迟有着严格的要求。在这种情况下采用经过优化后的低延迟版本可以显著改善用户体验并确保数据能够及时得到处理。 #### 下载途径 获取适合开发或生产的稳定版低延迟内核镜像文件通常可以从官方源码仓库或者第三方维护者处获得。Ubuntu等发行版也提供了预构建好的包来简化安装过程;而对于希望深入定制化需求的人来说,则可以直接从kernel.org下载最新的tarball,并按照文档说明完成后续操作。 #### 实际应用案例 Web服务器如Nginx在高负载条件下可能会频繁调用zlib库来进行HTTP压缩工作,这期间如果启用了低延迟特性则有助于减轻CPU负担并加快页面加载速度。通过工具如`perf top`观察到的相关函数(如`longest_match`, `deflate_slow` 和 `compress_block`),可以看出这些活动确实发生在实际运行环境中[^2]。 ```bash sudo apt-get install linux-lowlatency ``` 上述命令展示了如何在一个基于Debian/Ubuntu系统上快速部署已预先调整好默认值的低延迟内核环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值