内核开发基础-如何使用内核延时

简介: 从事Linux内核开发特别是驱动开发的小伙伴,肯定需要经常使用到定时器,比如,按键的去抖、LED屏幕显存buffer的刷新等。同时,在控制硬件时,可能会用到十分精确地短延时,这时,定时器的精度就不能满足这种需求了,这时就会使用到高精度定时器和忙等延时。今天就来简要说一下如何正确的使用内核提供的delay和sleep函数。

从事Linux内核开发特别是驱动开发的小伙伴,肯定需要经常使用到定时器,比如,按键的去抖、LED屏幕显存buffer的刷新等。同时,在控制硬件时,可能会用到十分精确地短延时,这时,定时器的精度就不能满足这种需求了,这时就会使用到高精度定时器和忙等延时。今天就来简要说一下如何正确的使用内核提供的delay和sleep函数。


这篇文章面对的读者是从事与驱动程序开发,但是,对于内核delay和sleep实现机制不是很熟悉的开发人员。


如何插入delays


首先,你需要回答一个问题,“需要使用delay的代码存在于原子性的上下文中吗?”或者“是否真的需要在原子性的上下文中插入delay吗?”。对于初学者来说,可能对于原子性的上下文不是很理解,下面简要解释一下。


对于任何Linux程序来说,无非运行于以下几种上下文之中:1)进程-用户空间上下文; 2)进程-内核空间上下文;3)硬件中断上下文;4)软件中断上下文;其中,3)和4)为原子性的上下文,其使用遵循以下几种原则:


  1. 不允许访问用户空间。因为其没有处于任何进程上下文之中,而用户空间都是依附于进程上下文的,所以,原子性上下文中,无法将任何进程与用户空间关联;


  1. 原子性的上下文中,使用current指针是没有任何意义的。current指针指向当前的任务(进程或者线程),而原子性的上下文不与任何进程有关系;


  1. 不能执行任何休眠或者调度。原子性的上下文中,不能调用任何可能会引起进程切换、调度、休眠的函数,比如schedul、wait_event、kmalloc、copy_from_user、msleep、del_timer_sync等等。


原子性上下文


好了,解释了原子性的上下文之后,我们言归正传,继续说一下,原子性的上下文中延时函数都有哪些。


ndelay(unsigned long nsecs)
udelay(unsigned long usecs)
mdelay(unsigned long msecs)


这三个函数原理,都是通过使CPU处于忙等状态,直到指定的指令周期执行完毕。其中,mdelay函数是udelay函数的简单封装。ndelay不是在所有平台上都能达到ns的延时精度。


这三个函数一般用在需要延时很短时间的硬件驱动程序中,比如,等待网卡寄存器初始化完成,等待直流电机启动完成等。


一般情况下,mdelay是不推荐使用的,msleep是较好的替代方式。


非原子性上下文


非原子性上下文,应该使用*sleep[_range]函数族,该函数族中的任何函数都能正确执行,“合理的”使用这些函数,可以帮助调度器、电源管理模块、驱动程序更好的工作。


-- 基于忙等:
  udelay(unsigned long usecs)
-- 基于hrtimers高分辨率定时器:
  usleep_range(unsigned long min, unsigned long max)
-- 基于jiffies / legacy_timers
  msleep(unsigned long msecs)
  msleep_interruptible(unsigned long msecs)


除了udelay函数,其他函数都会使调用进程睡眠,从而被调度出去,这是合理的,因为简单的忙等会浪费大量的CPU时间,从而严重的降低系统性能。


使用惯例


对于不同的延时时间,使用何种延时函数,内核提供了一些惯例,下面一一说明一下。


延时几微妙(< 10us)


使用udelay


  • 为何选用udelay? 对于嵌入式系统或者speed-steped PC,使用基于hrtimer实现的usleep,往往得不偿失,不过,这依赖于具体的使用环境而定,不过,你需要注意到这一点。


延时几毫秒(10us~20ms)


使用usleep_range


  • 为何不使用msleep(1ms20ms)?原始的解析,一般情况下,msleep(1ms20ms)往往不会达到使用者预期,其延时时长一般会稍微长于1ms~20ms,这对精度十分敏感的应用来说是不可接受的。


  • 为何不存在usleep函数? 因为usleep_range基于hrtimer实现,所以其有很好的精度,而usleep会引起大量的中断,从而降低系统性能。


  • 什么是合理的range?


通过引入范围,调度程序可以自由地将您的唤醒与由于其他原因而发生的任何其他唤醒结合在一起,或者在最坏的情况下,为您的上限触发中断。


您提供的范围越大,则不会触发中断的机会就越大; 这应该与特定代码路径在延迟/性能上可接受的上限之间取得平衡。 此处的精确公差是非常具体的情况,因此,由调用者确定一个合理的范围。


延时较大的毫秒(> 10ms)


使用msleep或者msleep_interruptible


  • msleep和msleep_interruptible的区别?


msleep将当前任务设置为TASK_UNINTERRUPTIBLE,而msleep_interruptible将当前任务设置为TASK_INTERRUPTIBLE,然后调度睡眠。 简而言之,区别在于睡眠是否可以通过信号提前结束。 通常,除非知道需要使用可中断的变体,否则请使用msleep。



相关文章
|
11月前
|
Linux 编译器 API
深度剖析Linux内核同步机制:实现高效可靠的并发编程
深度剖析Linux内核同步机制:实现高效可靠的并发编程
|
5月前
|
机器学习/深度学习 人工智能 负载均衡
深度解析:Linux内核调度策略的演变与优化
【5月更文挑战第30天】 随着计算技术的不断进步,操作系统的性能调优成为了提升计算机系统效率的关键。在众多操作系统中,Linux因其开源和高度可定制性而备受青睐。本文将深入剖析Linux操作系统的内核调度策略,追溯其历史演变过程,并重点探讨近年来为适应多核处理器和实时性要求而产生的调度策略优化。通过分析比较不同的调度算法,如CFS(完全公平调度器)、实时调度类和批处理作业的调度需求,本文旨在为系统管理员和开发者提供对Linux调度机制深层次理解,同时指出未来可能的发展趋势。
|
1月前
|
Linux API 调度
关于在Linux内核中使用不同延迟/休眠机制 【ChatGPT】
关于在Linux内核中使用不同延迟/休眠机制 【ChatGPT】
|
4月前
|
消息中间件 存储 监控
实战Linux I/O多路复用:借助epoll,单线程高效管理10,000+并发连接
本文介绍了如何使用Linux的I/O多路复用技术`epoll`来高效管理超过10,000个并发连接。`epoll`允许单线程监控大量文件描述符,显著提高了资源利用率。文章详细阐述了`epoll`的几个关键接口,包括`epoll_create`、`epoll_ctl`和`epoll_wait`,以及它们在处理并发连接中的作用。此外,还探讨了`epoll`在高并发TCP服务场景的应用,展示了如何通过`epoll`和线程/协程池来构建服务框架。
445 10
|
5月前
|
负载均衡 算法 Linux
深度解析:Linux内核调度器的演变与优化策略
【4月更文挑战第5天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分——内核调度器。文章将首先回顾Linux内核调度器的发展历程,从早期的简单轮转调度(Round Robin)到现代的完全公平调度器(Completely Fair Scheduler, CFS)。接着,分析当前CFS面临的挑战以及社区提出的各种优化方案,最后提出未来可能的发展趋势和研究方向。通过本文,读者将对Linux调度器的原理、实现及其优化有一个全面的认识。
211 8
|
5月前
|
数据采集 缓存 Linux
Linux C++ 应用开发:在Linux单线程应用中精确把握空闲时机
Linux C++ 应用开发:在Linux单线程应用中精确把握空闲时机
100 1
|
10月前
|
网络协议 Linux Android开发
【Linux高性能服务器编程】I/O复用的高级应用
【Linux高性能服务器编程】I/O复用的高级应用
71 0
【Linux高性能服务器编程】I/O复用的高级应用
|
缓存 固态存储 Ubuntu
十七、Linux性能优化实战学习笔记-如何利用系统缓存优化程序的运行效率?
Buffer 和Cache 的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速CPU 之间的桥梁,可以加速 I/O 的访问速度。
269 0
|
存储 缓存 Linux
嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(二)——并发与同步
嵌入式实践教程--【Linux驱动】Linux驱动开发基于Linux4.0+(二)——并发与同步
带你读《C/OS-III内核实现与应用开发实战指南:基于STM32》之二:裸机系统与多任务系统
本书分为两部分,第一部分先教你如何从0到1把uC/OS-III内核写出来,从底层的汇编开始讲解任务如何定义、如何切换,还讲解了阻塞延时如何实现、如何支持多优先级、如何实现任务延时列表以及时间片等uC/OS的核心知识点;第二部分讲解uC/OS-III内核组件的应用以及使用uC/OS-III进行多任务编程。
下一篇
无影云桌面