summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel/process.c')
-rw-r--r--arch/alpha/kernel/process.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 354597ba2..0390e3138 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -406,3 +406,35 @@ out:
unlock_kernel();
return error;
}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long schedule_frame;
+ unsigned long pc;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+ /*
+ * This one depends on the frame size of schedule(). Do a
+ * "disass schedule" in gdb to find the frame size. Also, the
+ * code assumes that sleep_on() follows immediately after
+ * interruptible_sleep_on() and that add_timer() follows
+ * immediately after interruptible_sleep(). Ugly, isn't it?
+ * Maybe adding a wchan field to task_struct would be better,
+ * after all...
+ */
+
+ pc = thread_saved_pc(&p->thread);
+ if (pc >= first_sched && pc < last_sched) {
+ schedule_frame = ((unsigned long *)p->thread.ksp)[6];
+ return ((unsigned long *)schedule_frame)[12];
+ }
+ return pc;
+}