diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/Makefile | 5 | ||||
| -rw-r--r-- | kernel/exit.c | 10 | ||||
| -rw-r--r-- | kernel/profile.c | 91 |
3 files changed, 101 insertions, 5 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index b3fce6d3ac9c..8e18771791de 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,9 +3,10 @@ # export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \ - printk.o platform.o suspend.o dma.o module.o cpufreq.o + printk.o platform.o suspend.o dma.o module.o cpufreq.o \ + profile.o -obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ +obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ module.o exit.o itimer.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o diff --git a/kernel/exit.c b/kernel/exit.c index 6ed07def4c62..c2b0f6eeff0f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -19,6 +19,7 @@ #include <linux/file.h> #include <linux/binfmts.h> #include <linux/ptrace.h> +#include <linux/profile.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -59,11 +60,12 @@ void release_task(struct task_struct * p) { struct dentry *proc_dentry; task_t *leader; - - if (p->state < TASK_ZOMBIE) - BUG(); + + BUG_ON(p->state < TASK_ZOMBIE); + if (p != current) wait_task_inactive(p); + atomic_dec(&p->user->processes); security_ops->task_free_security(p); free_uid(p->user); @@ -635,6 +637,8 @@ NORET_TYPE void do_exit(long code) current->comm, current->pid, preempt_count()); + profile_exit_task(tsk); + fake_volatile: acct_process(code); __exit_mm(tsk); diff --git a/kernel/profile.c b/kernel/profile.c new file mode 100644 index 000000000000..7ebffe971ca8 --- /dev/null +++ b/kernel/profile.c @@ -0,0 +1,91 @@ +/* + * linux/kernel/profile.c + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/profile.h> +#include <linux/bootmem.h> +#include <linux/notifier.h> +#include <linux/mm.h> + +/* Profile event notifications */ + +#ifdef CONFIG_PROFILING + +static DECLARE_RWSEM(profile_rwsem); +static struct notifier_block * exit_task_notifier; +static struct notifier_block * exit_mmap_notifier; +static struct notifier_block * exec_unmap_notifier; + +void profile_exit_task(struct task_struct * task) +{ + down_read(&profile_rwsem); + notifier_call_chain(&exit_task_notifier, 0, task); + up_read(&profile_rwsem); +} + +void profile_exit_mmap(struct mm_struct * mm) +{ + down_read(&profile_rwsem); + notifier_call_chain(&exit_mmap_notifier, 0, mm); + up_read(&profile_rwsem); +} + +void profile_exec_unmap(struct mm_struct * mm) +{ + down_read(&profile_rwsem); + notifier_call_chain(&exec_unmap_notifier, 0, mm); + up_read(&profile_rwsem); +} + +int profile_event_register(enum profile_type type, struct notifier_block * n) +{ + int err = -EINVAL; + + down_write(&profile_rwsem); + + switch (type) { + case EXIT_TASK: + err = notifier_chain_register(&exit_task_notifier, n); + break; + case EXIT_MMAP: + err = notifier_chain_register(&exit_mmap_notifier, n); + break; + case EXEC_UNMAP: + err = notifier_chain_register(&exec_unmap_notifier, n); + break; + } + + up_write(&profile_rwsem); + + return err; +} + + +int profile_event_unregister(enum profile_type type, struct notifier_block * n) +{ + int err = -EINVAL; + + down_write(&profile_rwsem); + + switch (type) { + case EXIT_TASK: + err = notifier_chain_unregister(&exit_task_notifier, n); + break; + case EXIT_MMAP: + err = notifier_chain_unregister(&exit_mmap_notifier, n); + break; + case EXEC_UNMAP: + err = notifier_chain_unregister(&exec_unmap_notifier, n); + break; + } + + up_write(&profile_rwsem); + return err; +} + +#endif /* CONFIG_PROFILING */ + +EXPORT_SYMBOL_GPL(profile_event_register); +EXPORT_SYMBOL_GPL(profile_event_unregister); |
