• 4412 Linux定时器


    一、Linux定时器基础知识

    1.1 定时器的使用范围

    延后执行某个操作,定时查询某个状态;前提是对时间要求不高的地方

    1.2 内核时间概念

    • Hz:(系统时钟通过CONFIG_HZ来设置,范围是100-1000;HZ决定使用中断发生的频率)

      • 1/200 = 5ms,说明4412中是5ms产生一次时钟中断。如果就没有定义的话,默认是100
    • 内核的全局变量jiffies:(记录内核自启动来的节拍数,内核之启动以来,产生的中断数)时钟中断,每产生一个中断,jiffies就加1。
    • jiffies/HZ:jiffies除以Hz得到内核自启动以来的秒数


    2.1 内核定时器的例程

    结构体timer_list,函数setup_timer,add_timer,del_timer,mod_timer

    struct timer_list {
        /*
         * All fields that change during normal runtime grouped to the
         * same cacheline
         */
        struct list_head entry;
        unsigned long expires;
        struct tvec_base *base;
    
        void (*function)(unsigned long);
        unsigned long data;
    
        int slack;
    
    #ifdef CONFIG_TIMER_STATS
        int start_pid;
        void *start_site;
        char start_comm[16];
    #endif
    #ifdef CONFIG_LOCKDEP
        struct lockdep_map lockdep_map;
    #endif
    };
    timer_list

    timer_list参数

    • struct list_head entry双向链表
    • unsigned long expires:超时时间,记录什么时候产生时钟中断
    • struct tvec_base *base:管理时钟的结构体
    • void *(function)(unsigned long):时钟中断产生之后的动作
    • unsigned long data:传递的参数
    #define setup_timer(timer, fn, data)                    
        do {                                
            static struct lock_class_key __key;         
            setup_timer_key((timer), #timer, &__key, (fn), (data));
        } while (0)
    
    void add_timer(struct timer_list *timer);
    int del_timer(struct timer_list * timer);
    int mod_timer(struct timer_list *timer, unsigned long expires);

    2.2 双向链表

    platform_driver_register→driver_register

    →bus_add_driver

    →struct bus_type *bus

    →struct subsys_private *p

    →struct kset subsys→struct list_head list;

    2.3 mod_timer相当于

    mod_timer = del_timer(time);timer->expires = expires;add_timer(timer);

    3 内核定时器实现的分析

    从内核定时器初始化到定时器例程

    3.1 add_timer如何添加定时器

            add_timer→mod_timer
            →__mod_timer(内核函数有下划线,表示“局部函数”)
            →internal_add_timer

    3.2 struct tvec_base *base结构体分析--管理内核时钟的结构体

            struct tvec_base {
                spinlock_t lock;    //自旋锁
                struct timer_list *running_timer;    //内核中正在处理的定时器
                unsigned long timer_jiffies;        //内核目前正在处理的定时器时间
                unsigned long next_timer;    
                struct tvec_root tv1;
                {
                    struct list_head vec[TVR_SIZE];//256长度数组
                    TVR_SIZE→#define TVR_SIZE (1 << TVR_BITS)
                    TVR_BITS=8;
                    宏定义CONFIG_BASE_SMALL=0
                    TVR_SIZE = 256
                }
                struct tvec tv2;    //64长度数组
                struct tvec tv3;
                struct tvec tv4;
                struct tvec tv5;
            }

    per_cpu 与CPU核多少有关    
    DEFINE_PER_CPU看到这样的变量,就表明这个变量是和CPU核相关的。

    有一些宏定义是在内核目录的config文件配置的 

    3.3 internal_add_timer

    分析idx参数
    如果idx<256,则将time_list添加到TV1
    如果idx<256*64,则将time_list添加到TV2
    如果idx<256*64*64,则将time_list添加到TV3
    如果idx<256*64*64*64,则将time_list添加到TV4
    如果idx > 0xffffffffUL,则将time_list添加到TV5

    3.4 list_add_tail

    双向链表操作函数都在include/linux/list.h文件中

  • 相关阅读:
    Ubuntu16.04安装openldap和phpldapadmin
    Java 8 中的抽象类和接口到底有啥区别?
    Redis 开发陷阱及避坑指南!
    Java 中的 6 颗语法糖
    Java 8 有多牛逼?打破一切你对接口的认知!
    Git操作常用的命令都在这里了。
    Github 太狠了,居然把 "master" 干掉了!
    微服务业务日志收集方案,写得非常好!
    Maven基本介绍与安装
    IntelliJ IDEA 调试 Java 8 Stream,实在太香了!
  • 原文地址:https://www.cnblogs.com/ch122633/p/9540141.html
Copyright © 2020-2023  润新知