歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux設備驅動之定時與延時

Linux設備驅動之定時與延時

日期:2017/2/28 13:46:11   编辑:Linux教程

Linux通過系統硬件定時器以規律的間隔(由HZ度量)產生定時器中斷,每次中斷使得一個內核計數器的值jiffies累加,因此這個jiffies就記錄了系統啟動開始的時間流逝,然後內核據此實現軟件定時器和延時。

Demo for jiffies and HZ

    #include <linux/jiffies.h>

    unsigned long j, stamp_1, stamp_half, stamp_n;

    j = jiffies; /* read the current value */
    stamp_1 = j + HZ; /* 1 second in the future */
    stamp_half = j + HZ/2; /* half a second */
    stamp_n = j + n * HZ / 1000; /* n milliseconds */

內核定時器

硬件時鐘中斷處理程序會喚起 TIMER_SOFTIRQ 軟中斷,運行當前處理器上到期的所有內核定時器。

定時器定義/初始化

在Linux內核中,timer_list結構體的一個實例對應一個定時器:

    /* 當expires指定的定時器到期時間期滿後,將執行function(data) */
    struct timer_list {
        unsigned long expires;           /*定時器到期時間*/
        void (*function)(unsigned long); /* 定時器處理函數 */
        unsigned long data;              /* function的參數 */
        ...
    };

    /* 定義 */
    struct timer_list my_timer;

    /* 初始化函數 */
    void init_timer(struct timer_list * timer);
    /* 初始化宏 */
    TIMER_INITIALIZER(_function, _expires, _data)

    /* 定義並初始化宏 */
    DEFINE_TIMER(_name, _function, _expires, _data)

定時器添加/移除

    /* 注冊內核定時器,將定時器加入到內核動態定時器鏈表中 */
    void add_timer(struct timer_list * timer);

    /* del_timer_sync()是 del_timer()的同步版,在刪除一個定時器時需等待其被處理完,
       因此該函數的調用不能發生在中斷上下文 */
    void del_timer(struct timer_list * timer);
    void del_timer_sync(struct timer_list * timer);

定時時間修改

    int mod_timer(struct timer_list *timer, unsigned long expires);

延時

短延時

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

內核在啟動時,會運行一個延遲測試程序(delay loop calibration),計算出lpj(loops per jiffy),根據lpj就實現了這幾個函數,屬忙等待。

長延時

  • 一個很直觀的方法是比較當前的 jiffies 和目標 jiffies:

    int time_after(unsigned long a, unsigned long b);    /* a after b, true */
    int time_before(unsigned long a, unsigned long b);   /* a before b */
    int time_after_eq(unsigned long a, unsigned long b); /* a after or equal b */
    int time_before_eq(unsigned long a, unsigned long b);/* a before or equal b */
  • 睡著延時

    void msleep(unsigned int millisecs);
    unsigned long msleep_interruptible(unsigned int millisecs);
    void ssleep(unsigned int seconds);

    Tip: msleep()、 ssleep()不能被打斷。

Copyright © Linux教程網 All Rights Reserved