diff options
Diffstat (limited to 'arch/alpha/kernel/process.c')
-rw-r--r-- | arch/alpha/kernel/process.c | 32 |
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; +} |