summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c18
-rw-r--r--kernel/power/Kconfig14
-rw-r--r--kernel/power/main.c36
3 files changed, 68 insertions, 0 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index b6cce14ba047..19615bcae7fe 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -147,6 +147,9 @@ struct kmem_cache *vm_area_cachep;
/* SLAB cache for mm_struct structures (tsk->mm) */
static struct kmem_cache *mm_cachep;
+/* Notifier list called when a task struct is freed */
+static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
+
static void account_kernel_stack(struct thread_info *ti, int account)
{
struct zone *zone = page_zone(virt_to_page(ti));
@@ -177,6 +180,20 @@ static inline void put_signal_struct(struct signal_struct *sig)
free_signal_struct(sig);
}
+int task_free_register(struct notifier_block *n)
+{
+ return atomic_notifier_chain_register(&task_free_notifier, n);
+}
+
+EXPORT_SYMBOL(task_free_register);
+
+int task_free_unregister(struct notifier_block *n)
+{
+ return atomic_notifier_chain_unregister(&task_free_notifier, n);
+}
+
+EXPORT_SYMBOL(task_free_unregister);
+
void __put_task_struct(struct task_struct *tsk)
{
WARN_ON(!tsk->exit_state);
@@ -187,6 +204,7 @@ void __put_task_struct(struct task_struct *tsk)
delayacct_tsk_free(tsk);
put_signal_struct(tsk->signal);
+ atomic_notifier_call_chain(&task_free_notifier, 0, tsk);
if (!profile_handoff_task(tsk))
free_task(tsk);
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index ca6066a6952e..631de1141247 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -123,6 +123,20 @@ config PM_TEST_SUSPEND
You probably want to have your system's RTC driver statically
linked, ensuring that it's available when this test runs.
+config SUSPEND_DEVICE_TIME_DEBUG
+ bool "Warnning device suspend/resume takes too much time"
+ depends on SUSPEND && PM_DEBUG
+ default n
+ ---help---
+ This option will enable a timing function to check device
+ suspend time consumption, If the device takes more time that
+ the threshold(default 0.5 ms), it will print the device and
+ bus name on the console. You can change the threshold
+ on-the-fly by modify /sys/power/time_threshold the time unit
+ is in microsecond.
+
+ This options only for debug proprose, If in doubt, say N.
+
config SUSPEND_FREEZER
bool "Enable freezer for suspend to RAM/standby" \
if ARCH_WANTS_FREEZER_CONTROL || BROKEN
diff --git a/kernel/power/main.c b/kernel/power/main.c
index b58800b21fc0..bfb684a4d412 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -229,11 +229,47 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
power_attr(pm_trace);
#endif /* CONFIG_PM_TRACE */
+#ifdef CONFIG_SUSPEND_DEVICE_TIME_DEBUG
+/*
+ * threshold of device suspend time consumption in microsecond(0.5ms), the
+ * driver suspend/resume time longer than this threshold will be
+ * print to console, 0 to disable */
+int device_suspend_time_threshold;
+
+static ssize_t
+device_suspend_time_threshold_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ if (device_suspend_time_threshold == 0)
+ return sprintf(buf, "off\n");
+ else
+ return sprintf(buf, "%d usecs\n",
+ device_suspend_time_threshold);
+}
+
+static ssize_t
+device_suspend_time_threshold_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int val;
+ if (sscanf(buf, "%d", &val) > 0) {
+ device_suspend_time_threshold = val;
+ return n;
+ }
+ return -EINVAL;
+}
+power_attr(device_suspend_time_threshold);
+#endif
+
static struct attribute * g[] = {
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
+#ifdef CONFIG_SUSPEND_DEVICE_TIME_DEBUG
+ &device_suspend_time_threshold_attr.attr,
+#endif
#ifdef CONFIG_PM_SLEEP
&pm_async_attr.attr,
#ifdef CONFIG_PM_DEBUG