电竞比分网-中国电竞赛事及体育赛事平台

分享

watchdog(二)

 老匹夫 2015-05-21

如果CPU可以響應(yīng)中斷,但是在長時間內(nèi)不能調(diào)度(比如禁止搶占時間太長),此時就需要一種機(jī)制(softlockup)來檢測這種情形。

本文基于3.14.25

記錄下第二種比較嚴(yán)重的“死鎖”:禁止搶占的時間太長,此時依舊可以相應(yīng)中斷,但是本CPU上在長時間內(nèi)沒有發(fā)生調(diào)度。                      
檢測機(jī)制:softlockup

復(fù)制代碼
reset_init
|-->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

kernel_init
|-->kernel_init_freeable();
    |-->lockup_detector_init();
        |-->watchdog_enable_all_cpus(false);
            |-->smpboot_register_percpu_thread(&watchdog_threads);
復(fù)制代碼

 

復(fù)制代碼
static struct smp_hotplug_thread watchdog_threads = {
    .store              = &softlockup_watchdog,                                                                                   
    .thread_should_run  = watchdog_should_run,
    .thread_fn          = watchdog,
    .thread_comm        = "watchdog/%u",
    .setup              = watchdog_enable,
};

smpboot_register_percpu_thread(&watchdog_threads)
|-->__smpboot_create_thread(&watchdog_threads, cpu);

165
static int __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu) 166 { 167 struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); 168 struct smpboot_thread_data *td; 169 +-- 4 lines: if (tsk)--- 173 td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu)); 174 +--- 2 lines: if (!td)--- 176 td->cpu = cpu; 177 td->ht = ht; 178 +-- 8 lines: tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu,---- 186 *per_cpu_ptr(ht->store, cpu) = tsk; 187 +-- 12 lines: if (ht->create) {--- 199 return 0; 200 }
復(fù)制代碼

 

復(fù)制代碼
創(chuàng)建了一個線程A task,該線程的主函數(shù)為 smpboot_thread_fun,該線程存儲于watchdog_threads.store中
過程(閱讀smpboot_thread_fn):
1、調(diào)用setup:watchdog_enable;
2、調(diào)用thread_should_run:watchdog_should_run判定是否需要運行線程主函數(shù)
3、線程主函數(shù)thread_fn:watchdog

watchdog_enable
|-->struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
|-->hrtimer->function = watchdog_timer_fn;
|-->hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL_PINNED);
|-->watchdog_set_prio(SCHED_FIFO, MAX_RT_PRIO - 1);//實時優(yōu)先級

這個函數(shù)比較重要,因為:
A task中主函數(shù)為smpboot_thread_fun,其中將會檢測是否運行thread_fn:watchdog
watchdog_should_run
|-->return __this_cpu_read(hrtimer_interrupts) != __this_cpu_read(soft_lockup_hrtimer_cnt);
因此如果hrtimer_interrupts == soft_lockup_hrtimer_cnt成立則運行調(diào)度器(放棄CPU使用權(quán)),否則運行thread_fn:watchdog

我們看下thread_fn的職責(zé):
watchdog:
|-->__this_cpu_write(soft_lockup_hrtimer_cnt, __this_cpu_read(hrtimer_interrupts));
|--> __this_cpu_write(watchdog_touch_ts, get_timestamp());

再看下hrtimer定時的職責(zé):
static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
|-->unsigned long touch_ts = __this_cpu_read(watchdog_touch_ts);
|-->__this_cpu_inc(hrtimer_interrupts); 記錄hrtimer中斷次數(shù)
|-->wake_up_process(__this_cpu_read(softlockup_watchdog));//喚醒創(chuàng)建的 A task,雖然被喚醒,但并不意味著就能得到調(diào)度
|-->hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period));
|-->duration = is_softlockup(touch_ts);//判定當(dāng)前時間與touch_ts的時間差是否超過20s,
|   如果超過,說明發(fā)生了softlockup,否則說明沒有發(fā)生。
復(fù)制代碼

 

總結(jié):更新watchdog_touch_ts的是一個具有實時優(yōu)先級的線程A task,既然是線程就存在是否得到調(diào)度的問題。如果在20s內(nèi),該線程沒有得到調(diào)度,則說
明發(fā)生了softlockup。因為按照原理來說,實時優(yōu)先級線程A task一定比普通優(yōu)先級線程先得到調(diào)度。如果一個線程B禁止調(diào)度長達(dá)20s,則無論如何
wake_up_process,A task都是不會被調(diào)度到的,即watchdog_touch_ts是不會得到更新的。而softlockup的檢測是放在一個hrtimer處理函數(shù)中的。關(guān)于該函數(shù)是在中斷上半部運行還是下半部運行,我還不清楚,但是由于其在中斷上下文運行,想必也是具有高”優(yōu)先級“的。
至于hrtimer的運行周期為:watchdog_thresh * 2 / 5 = 4s,我認(rèn)為只是加大了喚醒A task的次數(shù)(wake_up_process),畢竟在20s嘗試4次喚醒A task時,只要A task有一次得到調(diào)度的機(jī)會就可以更新 wathchdog_touch_ts,也就不會判定發(fā)生softlockup.

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多