zoukankan      html  css  js  c++  java
  • (笔记)Linux内核学习(八)之定时器和时间管理

    一 内核中的时间观念

           内核在硬件的帮助下计算和管理时间。硬件为内核提供一个系统定时器用以计算流逝的时间。系

     统定时器以某种频率自行触发,产生时钟中断,进入内核时钟中断处理程序中进行处理。

           墙上时间和系统运行时间根据时钟间隔来计算。

    利用时间中断周期执行的工作:

           更新系统运行时间;

           更新实际时间;

           在smp系统上,均衡调度程序中各处理器上运行队列;

           检查当前进程是否用尽了时间片,重新进行调度;

           运行超时的动态定时器;

           更新资源消耗和处理器时间的统计值;

    二 节拍率

           系统定时器的频率;通过静态预处理定义的——HZ;系统启动按照HZ值对硬件进行设置。体系结构不同,HZ值也不同;HZ可变的。

        //内核时间频率

        #define HZ 1000

    提高节拍率中断产生更加频繁带来的好处:

           提高时间驱动事件的解析度;

           提高时间驱动事件的准确度;

           内核定时器以更高的频度和准确度;

           依赖顶上执行的系统调用poll()和select()能更高的精度运行;

           系统时间测量更精细;

           提高进程抢占的准确度;

    提高节拍率带来的副作用:

           中断频率增高系统负担增加;

           中断处理程序占用处理器时间增多;

           频繁打断处理器高速缓存;

    节拍率HZ值需要在其中进行平衡。

    三 jiffies

      jiffies:全局变量,用来记录自系统启动以来产生的节拍总数。启动时内核将该变量初始化为0;

    此后每次时钟中断处理程序增加该变量的值。每一秒钟中断次数HZ,jiffies一秒内增加HZ。系统运行时间 = jiffie/HZ.

    jiffies用途:计算流逝时间和时间管理

    jiffies内部表示:

                  extern u64 jiffies_64;

                  extern unsigned long volatile jiffies;     //位长更系统有关32/64

      32位:497天后溢出

      64位:……

          

    复制代码
    复制代码
    //0.5秒后超时
    
    unsigned long timeout = jiffies + HZ/2;
    ……
    
    //注意jiffies值溢出回绕用宏time_before 而非 直timeout > jiffies
    if(time_before(jiffies,timeout)){
    
           //没有超时
    }else{
    
           //超时
    }
    复制代码
    复制代码

    四 硬时钟和定时器

      两种设备进行计时:系统定时器和实时时钟。

    实时时钟(RTC):用来持久存放系统时间的设备,即便系统关闭后,靠主板上的微型电池提供电力保持系统的计时。

        系统启动内核通过读取RTC来初始化墙上时间,改时间存放在xtime变量中。

    系统定时器:内核定时机制,注册中断处理程序,周期性触发中断,响应中断处理程序,进行处理执行以下工作:

      l  获得xtime_lock锁,访问jiffies和更新墙上时间xtime;

      l  更新实时时钟;

      l  更新资源统计值:当前进程耗时,系统时间等;

      l  执行已到期的动态定时器;

      l  执行scheduler_tick()

    复制代码
    复制代码
    //中断处理程序    
    irqreturn_t timer_interrupt(int irq, void *dev)
    {
        //ticks have passed
        long nticks;
    
        xtime_update(nticks);
    
        while (nticks--)
               update_process_times(user_mode(get_irq_regs()));
    
        return IRQ_HANDLED;
    }
     
    
    void xtime_update(unsigned long ticks)
    {
        //seq锁
        write_seqlock(&xtime_lock);
    
        do_timer(ticks);
    
        write_sequnlock(&xtime_lock);
    }
    
    void do_timer(unsigned long ticks)
    {
        jiffies_64 += ticks;
    
        //更新墙上时间 ——实际时间
        update_wall_time();
    
        calc_global_load(ticks);
    }
    
     
    
    void update_process_times(int user_tick)
    {
        struct task_struct *p = current;
    
        //计算当前进程执行时间
        account_process_tick(p, user_tick);
    
        //触发软中断TIMER_SOFTIRQ 超时的timer
        run_local_timers();
    
        //计算进程时间片
        scheduler_tick();
    
    }
    复制代码
    复制代码

    五 定时器

           定时器:管理内核时间的基础,推后或执行时间执行某些代码。

    定时器数据结构:

    复制代码
    复制代码
    struct timer_list {
                  struct list_head entry;
    
                  //定时值基于jiffies
                  unsigned long expires;
    
                  //定时器内部值
                  struct tvec_base *base;
    
                  //定时器处理函数
                  void (*function)(unsigned long);
    
                  //定时器处理函数参数
                  unsigned long data;
    
                  ……
           };
    复制代码
    复制代码

    定时器使用:

    复制代码
    复制代码
        struct timer_list my_timer;
    
           //初始化定时器
           init_timer(&my_timer);
    
           ……
          
           //激活定时器
           add_timer(&my_timer);
    
    
           //删除定时器
           del_timer(my_timer);
    
           ……
    复制代码
    复制代码

    六 延迟执行

           使用定时器和下半部机制推迟执行任务。还有其他延迟执行的机制:

    忙等待:

           利用节拍,精确率不高

           unsigned long delay = jiffies + 2*HZ ; //2秒 节拍整数倍才行;

           while(time_before(jiffies,delay))

                  ;

    短延迟:延迟时间精确到毫秒,微妙;短暂等待某个动作完成时,比时钟节拍更短;依靠数次循环达到延迟效果。

           void udelay(unsigned long usecs)

           void mdelay(unsigned long msecs)

    schedule_timeout()延迟:使执行的任务睡眠指定时间,达到延迟

    复制代码
    复制代码
    signed long __sched schedule_timeout(signed long timeout)
    {
           struct timer_list timer;
           unsigned long expire;
    
           switch (timeout)
           {
             case MAX_SCHEDULE_TIMEOUT:
    
                  //无限期睡眠
                  schedule();
                  goto out;
             default:
                  if (timeout < 0) {
                         current->state = TASK_RUNNING;
                         goto out;
                  }
           }
           //超时时间
           expire = timeout + jiffies;
    
           //初始化一个timer定时器 参数current task
           setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    
           __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);
    
           schedule();
    
           del_singleshot_timer_sync(&timer);
     
           /* Remove the timer from the object tracker */
           destroy_timer_on_stack(&timer);
           timeout = expire - jiffies;
     
     out:
           return timeout < 0 ? 0 : timeout;
    }
    
    
    static void process_timeout(unsigned long __data)
    {
           //唤醒被睡眠的任务
           wake_up_process((struct task_struct *)__data);
    }
    复制代码
  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/cyyljw/p/7880453.html
Copyright © 2011-2022 走看看