如果CPU可以响应中断,但是在长时间内不能调度(比如禁止抢占时间太长),此时就需要一种机制(softlockup)来检测这种情形。 本文基于3.14.25 记录下第二种比较严重的“死锁”:禁止抢占的时间太长,此时依旧可以相应中断,但是本CPU上在长时间内没有发生调度。 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);
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);
创建了一个线程A task,该线程的主函数为 smpboot_thread_fun,该线程存储于watchdog_threads.store中 过程(阅读smpboot_thread_fn): 1、调用setup:watchdog_enable; 2、调用thread_should_run:watchdog_should_run判定是否需要运行线程主函数 3、线程主函数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);//实时优先级 这个函数比较重要,因为: A task中主函数为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成立则运行调度器(放弃CPU使用权),否则运行thread_fn:watchdog 我们看下thread_fn的职责: watchdog: |-->__this_cpu_write(soft_lockup_hrtimer_cnt, __this_cpu_read(hrtimer_interrupts)); |--> __this_cpu_write(watchdog_touch_ts, get_timestamp()); 再看下hrtimer定时的职责: 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中断次数 |-->wake_up_process(__this_cpu_read(softlockup_watchdog));//唤醒创建的 A task,虽然被唤醒,但并不意味着就能得到调度 |-->hrtimer_forward_now(hrtimer, ns_to_ktime(sample_period)); |-->duration = is_softlockup(touch_ts);//判定当前时间与touch_ts的时间差是否超过20s, | 如果超过,说明发生了softlockup,否则说明没有发生。
总结:更新watchdog_touch_ts的是一个具有实时优先级的线程A task,既然是线程就存在是否得到调度的问题。如果在20s内,该线程没有得到调度,则说
|
|