• Linux内核设计与实现 第十一章 定时器和时间管理


    相对时间:如果某个事件在5s后被调度执行,那么系统所需要的是5s这个相对时间。
    绝对时间:如果要求管理当前日期和当前时间,那么内核不但要计算流逝的时间,而且还要计算绝对时间。

    系统定时器和时钟中断处理程序是Linux系统内核管理机制中的中枢。

    动态定时器:内核可以动态创建或撤销。是一种用来推迟执行程序的工具。

    11.1内核中的时间概念

    系统定时器是硬件,可以通过编程设定频率,这个频率叫节拍率。
    连续两次时钟中断的间隔时间称为节拍。
    内核通过控制时钟中断维护实际时间。
    系统运行时间:自系统启动开始所经过的时间。

    利用时间中断周期执行的工作:
    在这里插入图片描述
    在这里插入图片描述

    11.2节拍率:KH

    节拍率:单位时间系统时钟产生的节拍总数。
    定时器≈计数器,在音乐中,有一定强弱分别的一系列拍子在每隔一定时间重复出现。
    即弹钢琴时节拍这个动作是手指按下某个钢琴键;在操作系统中,节拍这个动作是定时器加一

    内核在文件中定义了节拍率。在启动时按照节拍率对硬件进行设置。
    内核需要用时钟中断处理许多内核任务,所以它对内核来说极为重要。
    内核中的全部时间概念都源于周期运行的系统时钟,所以选择一个合适的频率,就如同在人际交往中建立和谐关系一样,必须取得各方面的折中。

    不同体系结构的节拍率:
    在这里插入图片描述
    在这里插入图片描述

    1)理想的节拍率值

    在这里插入图片描述
    在这里插入图片描述

    2)高节拍率的优势

    在这里插入图片描述

    3)高节拍率的劣势

    在这里插入图片描述

    11.3jiffies

    jiffies:全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
    HK:节拍率是单位时间系统时钟产生的节拍总数。
    jiffies/HK=自系统启动以来产生的节拍的总数/单位时间系统时钟产生的节拍总数=自系统启动以来经过了多少个单位时间

    1)jiffies的内部表示

    jiffies的相关定义参考头文件

    /* 64bit和32bit的jiffies定义如下 */
    extern unsigned long jiffies;
    extern u64 jiffies_64;
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    2)jiffies的回绕

    定时器节拍数最大值为232-1或263-1。到达最大值会回绕到0。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    3)用户空间和节拍率

    Linux2.6开始内核定义了USER_HZ代表用户空间看到的HZ值。只要保持USER_HZ=HZ,用户空间认为的系统运行时间就等于实际系统运行时间。
    Linux2.6之前的内核不能改变内核HZ值。

    11.4硬时钟和定时器

    在这里插入图片描述

    1)实时时钟

    在这里插入图片描述

    2)系统定时器

    系统定时器的根本思想:提供一种周期性触发中断机制。有些体系结构是通过对电子晶振进行分频来实现。

    11.5时钟中断处理程序

    时钟中断处理程序每1/HZ秒都要发生一次,例如在x86机器上时钟中断处理程序每秒执行100次或1000次
    时钟中断处理程序可以划分为两个部分:与体系结构相关部分和与体系结构不相关部分
    与体系结构相关部分(绝大多数处理程序最低限度也要执行的工作):
    在这里插入图片描述

    与体系结构不相关部分,由函数tick_periodic()完成:
    在这里插入图片描述

    11.6实际时间

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    11.7定时器

    在这里插入图片描述

    1)使用定时器

    在这里插入图片描述
    内核提供了一组与定时器相关的接口,用来简单化管理定时器的操作:

    //1、定义初始化激活
    struct timer_list my_timer;//定义定时器。
    int_timer();//在使用定时器前,先初始化定时器数据结构的内部值。
    my_timer.expires = jiffies+delay;//定时器超时时的节拍数。
    my_timer.data = 0;//给定时器处理函数传入0值。
    my_timer.function = my_function;//定时器超时调用的函数。
    //定时器处理函数的函数原型。data参数使你可以利用同一个处理器函数注册多个定时器。通过data区别它们,如果不用这个参数,直接赋予0值。
    viod my_timer_function(unsigned long data);
    add_timer(&my_stimer);//激活定时器。
    
    //2、使用定时器
    mod_timer(&my_timer,jiffies+new_delay);//改变指定定时器超时时间
    
    
    del_temer(&my_timer);//返回1说明删除的定时器处于激活状态等待执行,但处于非活动状态,定时器能被成功删除;返回0说明删除的定时器已经处于活动状态或已经不存在,定时器无法删除。
    del_temer_sync(&my_timer);//返回1说明删除的定时器处于激活状态等待执行,但处于非活动状态,定时器能被成功删除;返回0说明删除的定时器已经处于活动状态或已经不存在,定时器无法删除。
    
    //已经超时的定时器A会被自动删除,即超时的定时器的定时器处理函数将运行,超时的定时器被自动删除前被进程A执行del_temer(&my_timer)删除,
    //进程A与定时器A的处理函数可能会交替执行,进程A认为自己删除了定时器A的处理函数,可能就会去访问定时器A的处理函数正在使用的数据。
    
    //在多处理器的SMP系统中,del_timer_sync函数要完成的任务除了同del_timer一样从定时器队列中删除一个定时器对象外,
    //还会确保当函数返回时系统中没有任何处理器正在执行定时器对象上的定时器处理函数,
    //而如果只是调用del_timer,那么当函数返回时,被删除的定时器对象的定时器函数可能正在其他处理器上运行。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2)定时器竞争条件

    在这里插入图片描述

    3)实现定时器

    Linux的内核定时器依赖于内核软中断,当系统硬件中断退出时,会遍历软件中断的使能位。并执行其关联的回调函数。
    实现定时器:内核在时钟中断发生后执行定时器,定时器作为软中断在上半部上下文中执行。
    时钟中断处理程序执行update_process_times()
    函数run_timer_softirq()处理软中断TIMER_SOFTIRQ,在当前处理器上运行所以超时定时器。

    超时定时器的搜索效率:
    在当前处理器上运行所有的超时定时器。为了提高搜索超时定时器的效率,内核将定时器按照超时时间划分为五组。当定时器超时时间接近时,定时器将随组一起下移。保证了定时器管理代码的高效性。

    11.8延迟执行

    在这里插入图片描述

    1)忙等待

    在这里插入图片描述
    在这里插入图片描述

    2)短延时

    jiffies:全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
    不使用jiffies的短延时函数:

    void udelay(unsigned long usecs)
    void ndelay(unsigned long nsecs)
    void mdelay(unsigned long msecs)
    
    • 1
    • 2
    • 3

    处理器空闲时在1秒中内能执行循环的次数,处理器售卖商家会公开。udelay和ndelay和mdelay函数根据指定延时在1秒中占的比例,就能决定需要在处理器空闲时进行多少次循环,即可达到要求的推迟时间。
    BogoMIPS:指处理器空闲时在1秒中内能执行循环的次数。
    处理器要空闲下来,就要禁止中断等。所以调用函数udelay和ndelay和mdelay会影响系统响应时间和性能。
    若非,必须要精确延时,只能调用udelay和ndelay和mdelay函数,其余时候都不调用。
    短延时函数原理其实也是忙等待。

    3)schedule_timeout()

    schedule_timeout()让需要延迟执行的任务,睡眠到指定的延迟时间耗尽后,再重新运行。该函数也只能尽量使睡眠时间接近指定的延时时间。
    schedule_timeout()函数会致使睡眠,因此调用代码必须处于进程上下文中,并且不能持有锁。
    schedule_timeout()函数会创建定时器,设置指定超时时间,超时处理函数process_timeout()会调用schedulel()。如果任务被提前唤醒,定时器将被撤销,process_timeout()函数返回剩余时间。
    在这里插入图片描述

  • 相关阅读:
    Ctrl A全屏复制+翻译乱码
    使用scp在多个linux系统间进行文件拷贝
    SharedPreferences()存储
    10:00面试,10:06就出来了,问的问题有点变态。。。
    基于STM32设计的智能家庭防盗系统(华为云IOT)(224)
    离子液体[C7MIm]TfS 1-庚基-3-甲基咪唑三氟甲磺酸盐 齐岳bio
    【产品设计】如何开展你的B端产品需求调研
    Pariatur sint mollitia odit eveniet.Dazu Name tragen.
    使用Docker安装深度学习环境,pytorch
    Qt Widget 删除之后还会显示 问题
  • 原文地址:https://blog.csdn.net/weixin_55255438/article/details/126872473