Linux 進程狀態中 TASK_UNINTERRUPTIBLE(D 狀態)不響應信號,僅能由 wake_up 喚醒。常見於 mutex 等待、I/O 等待。若硬體故障或死鎖導致長期無法調度,需機制檢測並告警——即 Hung Task Detector。
內核啟動時(subsys_initcall)創建 khungtaskd 內核執行緒,週期性(預設 120 秒)掃描所有任務:
nvcsw + nivcsw(自願+非自願切換計數)。TASK_UNINTERRUPTIBLE,判定為 Hung。sysctl_hung_task_panic 觸發 Kernel Panic。static int __init hung_task_init(void) {
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
watchdog_task = kthread_run(watchdog, NULL, "khungtaskd");
return 0;
}
static int watchdog(void *dummy) {
set_user_nice(current, 0);
for (;;) {
unsigned long timeout = sysctl_hung_task_timeout_secs;
while (schedule_timeout_interruptible(timeout_jiffies(timeout)))
timeout = sysctl_hung_task_timeout_secs;
if (atomic_xchg(&reset_hung_task, 0))
continue;
check_hung_uninterruptible_tasks(timeout);
}
}
static void check_hung_uninterruptible_tasks(unsigned long timeout) {
if (test_taint(TAINT_DIE) || did_panic) return;
rcu_read_lock();
for_each_process_thread(g, t) {
if (!max_count--) goto unlock;
if (t->state == TASK_UNINTERRUPTIBLE)
check_hung_task(t, timeout);
}
unlock:
rcu_read_unlock();
}
static void check_hung_task(struct task_struct *t, unsigned long timeout) {
unsigned long switch_count = t->nvcsw + t->nivcsw;
if (t->flags & (PF_FROZEN | PF_FREEZER_SKIP)) return;
if (!switch_count) return; // 新建未調度過
if (switch_count != t->last_switch_count) { // 有調度發生
t->last_switch_count = switch_count;
return;
}
// 無調度超過 timeout → 告警
trace_sched_process_hang(t);
if (!sysctl_hung_task_warnings) return;
if (sysctl_hung_task_warnings > 0) sysctl_hung_task_warnings--;
pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", t->comm, t->pid, timeout);
sched_show_task(t);
debug_show_held_locks(t);
touch_nmi_watchdog();
if (sysctl_hung_task_panic) {
trigger_all_cpu_backtrace();
panic("hung_task: blocked tasks");
}
}
Kernel hacking → Debug Lockups and Hangs → [*] Detect Hung Tasks
Default timeout: 120s
DEFINE_MUTEX(dlock);
static int __init dlock_init(void) {
mutex_lock(&dlock);
mutex_lock(&dlock); // 重複加鎖 → 進入 D 狀態永久等待
return 0;
}
[ 360.625466] INFO: task insmod:521 blocked for more than 120 seconds.
[ 360.631878] Tainted: G O 4.1.15 #5
[ 360.637042] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 360.644986] [] (__schedule) from [] (schedule+0x40/0xa4)
[ 360.652129] [] (schedule) from [] (schedule_preempt_disabled+0x18/0x1c)
[ 360.660570] [] (schedule_preempt_disabled) from [] (__mutex_lock_slowpath+0x6c/0xe4)
[ 360.670142] [] (__mutex_lock_slowpath) from [] (mutex_lock+0x44/0x48)
[ 360.678432] [] (mutex_lock) from [] (dlock_init+0x20/0x2c [dlock])
...
每 2 分鐘輸出一次,堆疊直指 mutex_lock → dlock_init,快速定位死鎖點。
Hung Task 機制以極低開銷提供 D 狀態死鎖可見性,驅動開發者只需收集告警日誌即可快速定位,建議生產環境啟用並調整 hung_task_timeout_secs、hung_task_warnings 避免日誌刷屏。