[原文链接]
http://hi.baidu.com/stealth_space/item/2007d93fe93ca28fb711dbac
接上篇 简单学习了解下 hung_task_timeout_secs 相关知识.
os: 2.6.18-194.32.1.el5 x86_64
# 先从系统中看下 hung_task 相关的参数及其参数值
[sina@localhost ~]$ sudo sysctl -a | grep hung
kernel.hung_task_warnings = 0
kernel.hung_task_timeout_secs = 120
kernel.hung_task_check_count = 4194304
kernel.hung_task_panic = 0
[sina@localhost ~]$
# 源码在此.... (v2.6.37.1) & 结合看下kernel/sysctl.c更好
# kernel/hung_task.c
/*
* detect hung task
*
* kernel/hung_task.c - kernel thread for detecting tasks stuck in d state
*/
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/nmi.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/sysctl.h>
* the number of tasks checked:
unsigned long __read_mostly sysctl_hung_task_check_count = pid_max_limit;
* limit number of tasks checked in a batch.
* this value controls the preemptibility of khungtaskd since preemption
* is disabled during the critical section. it also controls the size of
* the rcu grace period. so it needs to be upper-bound.
#define hung_task_batching 1024
* zero means infinite timeout - no checking done:
unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120;
unsigned long __read_mostly sysctl_hung_task_warnings = 10;
static int __read_mostly did_panic;
static struct task_struct *watchdog_task;
* should we panic (and reboot, if panic_timeout= is set) when a
* hung task is detected:
unsigned int __read_mostly sysctl_hung_task_panic =
config_bootparam_hung_task_panic_value;
static int __init hung_task_panic_setup(char *str)
{
sysctl_hung_task_panic = simple_strtoul(str, null, 0);
return 1;
}
__setup("hung_task_panic=", hung_task_panic_setup);
static int
hung_task_panic(struct notifier_block *this, unsigned long event, void *ptr)
did_panic = 1;
return notify_done;
static struct notifier_block panic_block = {
.notifier_call = hung_task_panic,
};
static void check_hung_task(struct task_struct *t, unsigned long timeout)
unsigned long switch_count = t->nvcsw + t->nivcsw;
/*
* ensure the task is not frozen.
* also, when a freshly created task is scheduled once, changes
* its state to task_uninterruptible without having ever been
* switched out once, it musn't be checked.
*/
if (unlikely(t->flags & pf_frozen || !switch_count))
return;
if (switch_count != t->last_switch_count) {
t->last_switch_count = switch_count;
}
if (!sysctl_hung_task_warnings)
sysctl_hung_task_warnings--;
* ok, the task did not get scheduled for more than 2 minutes,
* complain:
printk(kern_err "info: task %s:%d blocked for more than "
"%ld seconds.\n", t->comm, t->pid, timeout);
printk(kern_err "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
" disables this message.\n");
sched_show_task(t);
debug_show_held_locks(t);
touch_nmi_watchdog();
if (sysctl_hung_task_panic)
panic("hung_task: blocked tasks");
* to avoid extending the rcu grace period for an unbounded amount of time,
* periodically exit the critical section and enter a new one.
* for preemptible rcu it is sufficient to call rcu_read_unlock in order
* to exit the grace period. for classic rcu, a reschedule is required.
static void rcu_lock_break(struct task_struct *g, struct task_struct *t)
get_task_struct(g);
get_task_struct(t);
rcu_read_unlock();
cond_resched();
rcu_read_lock();
put_task_struct(t);
put_task_struct(g);
* check whether a task_uninterruptible does not get woken up for
* a really long time (120 seconds). if that happens, print out
* a warning.
static void check_hung_uninterruptible_tasks(unsigned long timeout)
int max_count = sysctl_hung_task_check_count;
int batch_count = hung_task_batching;
struct task_struct *g, *t;
* if the system crashed already then all bets are off,
* do not report extra hung tasks:
if (test_taint(taint_die) || did_panic)
do_each_thread(g, t) {
if (!max_count--)
goto unlock;
if (!--batch_count) {
batch_count = hung_task_batching;
rcu_lock_break(g, t);
/* exit if t or g was unhashed during refresh. */
if (t->state == task_dead || g->state == task_dead)
goto unlock;
}
/* use "==" to skip the task_killable tasks waiting on nfs */
if (t->state == task_uninterruptible)
check_hung_task(t, timeout);
} while_each_thread(g, t);
unlock:
static unsigned long timeout_jiffies(unsigned long timeout)
/* timeout of 0 will disable the watchdog */
return timeout ? timeout * hz : max_schedule_timeout;
* process updating of timeout sysctl
int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
int ret;
ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
if (ret || !write)
goto out;
wake_up_process(watchdog_task);
out:
return ret;
* kthread which checks for tasks stuck in d state
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;
check_hung_uninterruptible_tasks(timeout);
return 0;
static int __init hung_task_init(void)
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
watchdog_task = kthread_run(watchdog, null, "khungtaskd");
module_init(hung_task_init);
[ -eof- ]