diff options
author | San Mehat <san@google.com> | 2010-11-01 16:37:17 +0800 |
---|---|---|
committer | Lily Zhang <r58066@freescale.com> | 2010-11-22 09:39:20 +0800 |
commit | 80d83542ba7bac6233187defd8c3b70c602f6285 (patch) | |
tree | 91fe9267084511a361c3b9c2bb47564cbc7b09d3 | |
parent | 418f10aecea02315040eba4e3efbd56782f7bfaf (diff) |
Android sched: Add a generic notifier when a task struct is about to be freed
This patch adds a notifier which can be used by subsystems that may
be interested in when a task has completely died and is about to
have it's last resource freed.
The Android lowmemory killer uses this to determine when a task
it has killed has finally given up its goods.
Signed-off-by: San Mehat <san@google.com>
-rw-r--r-- | drivers/staging/android/lowmemorykiller.c | 19 | ||||
-rw-r--r-- | include/linux/sched.h | 3 | ||||
-rw-r--r-- | kernel/fork.c | 18 |
3 files changed, 40 insertions, 0 deletions
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 4235bc69e6c2..c242bb348f1a 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -63,6 +63,24 @@ static struct task_struct *lowmem_deathpending; printk(x); \ } while (0) +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data); + +static struct notifier_block task_nb = { + .notifier_call = task_notify_func, +}; + +static int +task_notify_func(struct notifier_block *self, unsigned long val, void *data) +{ + struct task_struct *task = data; + if (task == lowmem_deathpending) { + lowmem_deathpending = NULL; + task_free_unregister(&task_nb); + } + return NOTIFY_OK; +} + static int lowmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask) { struct task_struct *p; @@ -162,6 +180,7 @@ static int lowmem_shrink(struct shrinker *s, int nr_to_scan, gfp_t gfp_mask) selected->pid, selected->comm, selected_oom_adj, selected_tasksize); lowmem_deathpending = selected; + task_free_register(&task_nb); force_sig(SIGKILL, selected); rem -= selected_tasksize; } diff --git a/include/linux/sched.h b/include/linux/sched.h index 5ee397ee3bca..794b8f447d03 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1682,6 +1682,9 @@ static inline void put_task_struct(struct task_struct *t) extern void task_times(struct task_struct *p, cputime_t *ut, cputime_t *st); extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st); +extern int task_free_register(struct notifier_block *n); +extern int task_free_unregister(struct notifier_block *n); + /* * Per process flags */ 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); } |