patch-2.4.6 linux/arch/mips/kernel/process.c

Next file: linux/arch/mips/kernel/ptrace.c
Previous file: linux/arch/mips/kernel/proc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
@@ -162,21 +162,21 @@
 	long retval;
 
 	__asm__ __volatile__(
-		".set\tnoreorder\n\t"
-		"move\t$6,$sp\n\t"
-		"move\t$4,%5\n\t"
-		"li\t$2,%1\n\t"
-		"syscall\n\t"
-		"beq\t$6,$sp,1f\n\t"
-		"subu\t$sp,32\n\t"	/* delay slot */
-		"jalr\t%4\n\t"
-		"move\t$4,%3\n\t"	/* delay slot */
-		"move\t$4,$2\n\t"
-		"li\t$2,%2\n\t"
-		"syscall\n"
-		"1:\taddiu\t$sp,32\n\t"
-		"move\t%0,$2\n\t"
-		".set\treorder"
+		".set noreorder               \n"
+		"    move    $6,$sp           \n"
+		"    move    $4,%5            \n"
+		"    li      $2,%1            \n"
+		"    syscall                  \n"
+		"    beq     $6,$sp,1f        \n"
+		"    subu    $sp,32           \n"	/* delay slot */
+		"    jalr    %4               \n"
+		"    move    $4,%3            \n"	/* delay slot */
+		"    move    $4,$2            \n"
+		"    li      $2,%2            \n"
+		"    syscall                  \n"
+		"1:  addiu   $sp,32           \n"
+		"    move    %0,$2            \n"
+		".set reorder"
 		:"=r" (retval)
 		:"i" (__NR_clone), "i" (__NR_exit),
 		 "r" (arg), "r" (fn),
@@ -199,27 +199,47 @@
 #define first_sched	((unsigned long) scheduling_functions_start_here)
 #define last_sched	((unsigned long) scheduling_functions_end_here)
 
+/* get_wchan - a maintenance nightmare ...  */
 unsigned long get_wchan(struct task_struct *p)
 {
-	unsigned long schedule_frame;
-	unsigned long pc;
+	unsigned long frame, pc;
 
 	if (!p || p == current || p->state == TASK_RUNNING)
 		return 0;
 
 	pc = thread_saved_pc(&p->thread);
-	if (pc == (unsigned long) interruptible_sleep_on
-	    || pc == (unsigned long) sleep_on) {
-		schedule_frame = ((unsigned long *)p->thread.reg30)[9];
-		return ((unsigned long *)schedule_frame)[15];
-	}
-	if (pc == (unsigned long) interruptible_sleep_on_timeout
-	    || pc == (unsigned long) sleep_on_timeout) {
-		schedule_frame = ((unsigned long *)p->thread.reg30)[9];
-		return ((unsigned long *)schedule_frame)[16];
+	if (pc < first_sched || pc >= last_sched) {
+		return pc;
 	}
+
+	if (pc >= (unsigned long) sleep_on_timeout)
+		goto schedule_timeout_caller;
+	if (pc >= (unsigned long) sleep_on)
+		goto schedule_caller;
+	if (pc >= (unsigned long) interruptible_sleep_on_timeout)
+		goto schedule_timeout_caller;
+	if (pc >= (unsigned long)interruptible_sleep_on)
+		goto schedule_caller;
+	goto schedule_timeout_caller;
+
+schedule_caller:
+	frame = ((unsigned long *)p->thread.reg30)[9];
+	pc    = ((unsigned long *)frame)[11];
+	return pc;
+
+schedule_timeout_caller:
+	/* Must be schedule_timeout ...  */
+	pc    = ((unsigned long *)p->thread.reg30)[10];
+	frame = ((unsigned long *)p->thread.reg30)[9];
+
+	/* The schedule_timeout frame ...  */
+	pc    = ((unsigned long *)frame)[14];
+	frame = ((unsigned long *)frame)[13];
+
 	if (pc >= first_sched && pc < last_sched) {
-		printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__);
+		/* schedule_timeout called by interruptible_sleep_on_timeout */
+		pc    = ((unsigned long *)frame)[11];
+		frame = ((unsigned long *)frame)[10];
 	}
 
 	return pc;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)