]> git.hungrycats.org Git - linux/commitdiff
[PATCH] oprofile - hooks
authorJohn Levon <levon@movementarian.org>
Tue, 15 Oct 2002 11:30:26 +0000 (04:30 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 15 Oct 2002 11:30:26 +0000 (04:30 -0700)
This implements the simple hooks we need to catch unmappings, and to
make sure no stale task_struct*'s are ever used by the main oprofile
core mechanism.  If disabled, it compiles to nothing.

arch/i386/Config.help
arch/i386/config.in
include/linux/profile.h [new file with mode: 0644]
kernel/Makefile
kernel/exit.c
kernel/profile.c [new file with mode: 0644]
mm/mmap.c

index 299dea0c6536b54928c2291c2d83c43c9a4d4384..d6f3cdc95f05428709b93fc3373d2b47df5a9fca 100644 (file)
@@ -1048,6 +1048,11 @@ CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
 
+Profiling support
+CONFIG_PROFILING
+  Say Y here to enable the extended profiling support mechanisms used
+  by profilers such as OProfile.
 Software Suspend
 CONFIG_SOFTWARE_SUSPEND
   Enable the possibilty of suspendig machine. It doesn't need APM.
index 784e35d23bce96676fdd77dfe47d9f1a0a1caf5f..97a9b862d72f4440d5367994cf349a325fcf0bfa 100644 (file)
@@ -442,6 +442,13 @@ source drivers/usb/Config.in
 
 source net/bluetooth/Config.in
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Profiling support'
+   bool 'Profiling support (EXPERIMENTAL)' CONFIG_PROFILING
+   endmenu
+fi
 mainmenu_option next_comment
 comment 'Kernel hacking'
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff --git a/include/linux/profile.h b/include/linux/profile.h
new file mode 100644 (file)
index 0000000..15c1e91
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _LINUX_PROFILE_H
+#define _LINUX_PROFILE_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/errno.h>
+enum profile_type {
+       EXIT_TASK,
+       EXIT_MMAP,
+       EXEC_UNMAP
+};
+
+#ifdef CONFIG_PROFILING
+struct notifier_block;
+struct task_struct;
+struct mm_struct;
+/* task is in do_exit() */
+void profile_exit_task(struct task_struct * task);
+/* change of vma mappings */
+void profile_exec_unmap(struct mm_struct * mm);
+
+/* exit of all vmas for a task */
+void profile_exit_mmap(struct mm_struct * mm);
+
+int profile_event_register(enum profile_type, struct notifier_block * n);
+
+int profile_event_unregister(enum profile_type, struct notifier_block * n);
+#else
+
+static inline int profile_event_register(enum profile_type t, struct notifier_block * n)
+{
+       return -ENOSYS;
+}
+static inline int profile_event_unregister(enum profile_type t, struct notifier_block * n)
+{
+       return -ENOSYS;
+}
+#define profile_exit_task(a) do { } while (0)
+#define profile_exec_unmap(a) do { } while (0)
+#define profile_exit_mmap(a) do { } while (0)
+#endif /* CONFIG_PROFILING */
+#endif /* __KERNEL__ */
+#endif /* _LINUX_PROFILE_H */
index b3fce6d3ac9cb3b354c2eb21133f356d79d276ae..8e18771791dee429ae4cbeff8c6d5f88f18c199e 100644 (file)
@@ -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
index 6ed07def4c62ed389895e52626785278f7fa13c2..c2b0f6eeff0f157669d51cc8bccafbff47dfbf3f 100644 (file)
@@ -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 (file)
index 0000000..7ebffe9
--- /dev/null
@@ -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);
index 5d43e84413b16dac1a8f4ddd5d9bf63b46c46181..90ae8b22ab96cb3eb5bae9844a594b7a45c8963e 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -16,6 +16,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -1104,6 +1105,10 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
        if (mpnt->vm_start >= end)
                return 0;
 
+       /* Something will probably happen, so notify. */
+       if (mpnt->vm_file && (mpnt->vm_flags & VM_EXEC))
+               profile_exec_unmap(mm);
        /*
         * If we need to split any vma, do it now to save pain later.
         */
@@ -1253,7 +1258,10 @@ void exit_mmap(struct mm_struct * mm)
        mmu_gather_t *tlb;
        struct vm_area_struct * mpnt;
 
+       profile_exit_mmap(mm);
        release_segments(mm);
        spin_lock(&mm->page_table_lock);
 
        tlb = tlb_gather_mmu(mm, 1);