十。内核时间问题

        好久没有提笔写点东西,最近人有点堕落了。新在的公司老是给我一种养老的感觉。我得自己找点事情干的,要不这么年轻就废了多不好啊。所以就想起提笔写以下以前的一些学习内核的笔记。有什么问题望大家指正,大家一起学习。

############ 内核时间 ###############
1、延时
    for(i = 0; i < 100; i++);在内核中是不能使用这种延时,在编译的时候会被优化掉
    在内核中使用延时一定要使用内核的API

    类似与死循环延时,就是用for封装的函数

    jiffies 是全局变量,用来记录自系统启动以来产生的节拍总数
        定义在头文件 <path>/include/linux/jiffies.h

2、短延时:
        mdelay()ms级;
        udelay()us级;
        ndelay()ns级;对与当前的是不支持的,CPU的速度不够快,以后可能会达到;这个函数存在,但是不>要用,实现时就是mdelay或udelay;

3、长延时:
        使用 TIMER4 进行中断;根据HZ的值来初始化TIMER4,每秒调度器要醒来100次,时间片是10ms
        #define HZ #100
        unsigned long jiffies   //这个变量 1s 加 100 次,
            //jiffies 从内核启动就开始计数,初始值是 -5 * 60 * HZ(-5min);

            //jiffies 存的是补码,这样就是一个很大的值,+5min就是0了,这样jiffies 就溢出了,。这样可
以在你的程序依赖于jiffies时,5min后就会看出效果
        int tmp = jiffies + 2 * HZ
        while(jiffies < tmp);  //xxxxxxx,这是错的,jiffies是32位的,很容易就溢出了,下面的情况可保>证安全

        在延时时间不超过 248.5天的情况:
        while(time_before(jiffies, tmp));
        while(time_after(jiffies, tmp));

4、睡眠延时:(是放弃cpu睡眠,不是很精确,调度器是10ms才醒来一次,并且调度器的工作也需要消耗时间)
        msleep()
        ssleep()

        set_current_state(状态)
            //函数和程序状态的宏 --- 头文件 <include/linux/sched.h>
            //这个函数用于设置进程状态
            //TASK_INTERRUPTABLE:代表进程状态是不可打断的
        schedule_timeout()
            //手动启动调度器,需要手动的设置一下睡眠的状态

5、内核定时器:(软件实现的)
    timer_list 是基于jiffies实现的

    <-******timer_list 内的 func 处理函数是运行在中断上下文的******->

    定时器管理着链表的第一个链表,放的是还有一次中断就到期的中断处理函数(同时到期) jiffies+1
    第二个链表里是还有两次就到期的中断处理函数jiffies+2
    每个中断到来,内核都会遍历链表,然后把链表上挂的任务函数执行,最后把其它链表往上提一个,依次类推。

    核心头文件:<path>/include/linux/timer.h
        struct timer_list {
            struct list_head entry;
            unsigned long expires;  //到期的时间值;存放这jiffies + 2 * HZ,即 2s 后到期
            struct tvec_base *base; //指向维护定时器和做定时器迁移的链表

            void (*function)(unsigned long);    //处理函数
            unsigned long data; //作为上面函数的参数
            ...
        };

    函数:
    初始化除了结构体中会用到的 3 个(expires、function、data)的,其它全部初始化:
        init_timer()
    初始化,包括func和data:
        setup_timer()
    添加一个内核定时器:
        add_timer()
    相当于修改定时器的值(expires)和add_timer()两步
        mod_timer()

    从内核中删掉定时器:
        del_timer()
    在多核的时候,会等待其它核把定时器处理函数执行完,这个函数会睡眠:
        del_timer_sync()
    --->在单核的情况下,这两个函数是一样的,所以以后在用的时候都用下面这个就好

    这定时器在处理完之后,结构体就会被丢弃;所以想要连续不断的来定时,在处理函数中再添加一次内核定时
器即可

    使用方法:
        1:定义一个timer_list
        2:init_timer,初始化data,func,expires/setuptimer,初始化expires/mod_timer
        3:addtimer 把这个timer加到timer里
        4:创建任务函数实体(func)《有可能睡眠的函数在这里都不能使用,因为执行在中断上下文,不允许>中断》
        5:退出的时候del_timer()注销定时器

6、获得当前时间:
        do_gettimeofday()
        getnstimeofday()

################################################
# 确定必须运行在中断上下文的是:
#   中断处理函数
#   软中断处理函数
#   task_let
#   内核定时器处理函数
################################################





你可能感兴趣的:(定时器,jiffies,timer_list,内核时间)