linux核心中的定時器代碼簡介

來源:互聯網
上載者:User

    struct timer_list :軟體時鐘,記錄了軟體時鐘的到期時間以及到期後要執行的操作。具體的成員以及含義見表3-1。
    struct tvec_base :用於組織、管理軟體時鐘的結構。在 SMP 系統中,每個 CPU 有一個。具體的成員以及含義參見表3-2。

 

    表3-1 struct timer_list 主要成員
網域名稱     類型     描述
entry     struct list_head     所在的鏈表
expires     unsigned long     到期時間,以 tick 為單位
function     void (*)(unsigned long)     回呼函數,到期後執行的操作
data     unsigned long     回呼函數的參數
base     struct tvec_base *     記錄該軟體時鐘所在的 struct tvec_base 變數

    表3-2 struct tvec_base 類型的成員
網域名稱     類型     描述
lock     spinlock_t     用於同步操作
running_timer     struct timer_list *     正在處理的軟體時鐘
timer_jiffies     unsigned long     當前正在處理的軟體時鐘到期時間
tv1     struct tvec_root     儲存了到期時間從 timer_jiffies 到 timer_jiffies + 淺析Linux 時鐘處理機制(圖二)之間(包括邊緣值)的所有軟體時鐘
tv2     struct tvec     儲存了到期時間從 timer_jiffies + 淺析Linux 時鐘處理機制(圖三)到 timer_jiffies +淺析Linux 時鐘處理機制(圖四)之間(包括邊緣值)的 所有軟體時鐘
tv3     struct tvec     儲存了到期時間從 timer_jiffies +淺析Linux 時鐘處理機制(圖五)到 timer_jiffies +淺析Linux 時鐘處理機制(圖六)之間(包括邊緣值)的所有軟體時鐘
tv4     struct tvec     儲存了到期時間從 timer_jiffies +淺析Linux 時鐘處理機制(圖七)到 timer_jiffies +淺析Linux 時鐘處理機制(圖八)之間(包括邊緣值)的所有軟體時鐘
tv5     struct tvec     儲存了到期時間從 timer_jiffies +淺析Linux 時鐘處理機制(圖九)到 timer_jiffies +淺析Linux 時鐘處理機制(圖十)之間(包括邊緣值)的所有軟體時鐘

 

    其中 tv1 的類型為 struct tvec_root ,tv 2~ tv 5的類型為 struct tvec ,清單3-1顯示它們的定義

    清單3-1 struct tvec_root 和 struct tvec 的定義

 

struct tvec {
struct list_head vec[TVN_SIZE];
};

 

struct tvec_root {
struct list_head vec[TVR_SIZE];
};

可見它們實際上就是類型為 struct list_head 的數組,其中 TVN_SIZE 和 TVR_SIZE 在系統沒有配置宏 CONFIG_BASE_SMALL 時分別被定義為64和256。

/*
 * This function runs timers and the timer-tq in bottom half context.
 */
static void run_timer_softirq(struct softirq_action *h)
{
    tvec_base_t *base = __get_cpu_var(tvec_bases);

    hrtimer_run_queues();

    //首先在非強制中斷處理中判斷jiffies如果大於最近的定時器的到期時間base->timer_jiffies,就表示有定時器到期了
    //進入__run_timers(base)進行處理
    if (time_after_eq(jiffies, base->timer_jiffies))
        __run_timers(base);
}

/**
 * __run_timers - run all expired timers (if any) on this CPU.
 * @base: the timer vector to be processed.
 *
 * This function cascades all vectors and executes all expired timer
 * vectors.
 */
static inline void __run_timers(tvec_base_t *base)
{
    struct timer_list *timer;

    spin_lock_irq(&base->lock);
   
    //判斷jiffies是否大於當前定時器到期時間base->timer_jiffies,
    //base->timer_jiffies也就是到期時間最短的那個
    while (time_after_eq(jiffies, base->timer_jiffies)) {
        struct list_head work_list;
        struct list_head *head = &work_list;
       
        //最近定時器在tv1中的index,也就是jiffies的低6位
        int index = base->timer_jiffies & TVR_MASK;   

        /*
         * Cascade timers:
         */
        //如果tv1中index==0,表示tv1中定時器全部過時了,需要從tv2~tv5中取出256個jiffies的定時器填充tv1
        //也就是說每過256個tick,就會cascade一次,下面再介紹cascade
        if (!index &&
            (!cascade(base, &base->tv2, INDEX(0))) &&
                (!cascade(base, &base->tv3, INDEX(1))) &&
                    !cascade(base, &base->tv4, INDEX(2)))
            cascade(base, &base->tv5, INDEX(3));
           
        //為什麼加1?
        ++base->timer_jiffies;
        //tv1在index位置的定時器隊列,用work_list指向它,並把tv1中index的隊列頭設為空白
        list_replace_init(base->tv1.vec + index, &work_list);
        //如果取出的定時器隊列不為空白,需要處理定時器
        while (!list_empty(head)) {
            void (*fn)(unsigned long);
            unsigned long data;
           
            //找第一個timer
            timer = list_first_entry(head, struct timer_list,entry);
            fn = timer->function;
            data = timer->data;

            timer_stats_account_timer(timer);

            set_running_timer(base, timer);                //設為正在啟動並執行timer
            detach_timer(timer, 1);                        //刪除這個timer
            spin_unlock_irq(&base->lock);                //在執行timer回呼函數時,先釋放lock
            {
                int preempt_count = preempt_count();
                fn(data);                                //執行timer的函數
                if (preempt_count != preempt_count()) {
                    printk(KERN_WARNING "huh, entered %p "
                           "with preempt_count %08x, exited"
                           " with %08x?\n",
                           fn, preempt_count,
                           preempt_count());
                    BUG();
                }
            }
            spin_lock_irq(&base->lock);
        }
    }
    set_running_timer(base, NULL);                        //把正在啟動並執行timer設為空白
    spin_unlock_irq(&base->lock);
}

//取出tv2~tv5的定時器,放到tv1中
static int cascade(tvec_base_t *base, tvec_t *tv, int index)
{
    /* cascade all the timers from tv up one level */
    struct timer_list *timer, *tmp;
    struct list_head tv_list;

    list_replace_init(tv->vec + index, &tv_list);

    /*
     * We are removing _all_ timers from the list, so we
     * don't have to detach them individually.
     */
    list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
        BUG_ON(tbase_get_base(timer->base) != base);
        internal_add_timer(base, timer);
    }

    return index;
}

//tv2對應INDEX(0),即(jiffies>>8)&0x3f
//tv3對應INDEX(1),即(jiffies>>14)&0x3f
//tv4對應INDEX(2),即(jiffies>>20)&0x3f
//tv5對應INDEX(3),即(jiffies>>26)&0x3f
#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.