svn commit: r357334 - in head: share/man/man9 sys/amd64/amd64 sys/arm/arm sys/arm64/arm64 sys/i386/i386 sys/kern sys/mips/mips sys/powerpc/powerpc sys/riscv/riscv sys/sparc64/sparc64 sys/sys sys/x8...

Mark Johnston markj at FreeBSD.org
Fri Jan 31 15:43:37 UTC 2020


Author: markj
Date: Fri Jan 31 15:43:33 2020
New Revision: 357334
URL: https://svnweb.freebsd.org/changeset/base/357334

Log:
  Reimplement stack capture of running threads on i386 and amd64.
  
  After r355784 the td_oncpu field is no longer synchronized by the thread
  lock, so the stack capture interrupt cannot be delievered precisely.
  Fix this using a loop which drops the thread lock and restarts if the
  wrong thread was sampled from the stack capture interrupt handler.
  
  Change the implementation to use a regular interrupt instead of an NMI.
  Now that we drop the thread lock, there is no advantage to the latter.
  
  Simplify the KPIs.  Remove stack_save_td_running() and add a return
  value to stack_save_td().  On platforms that do not support stack
  capture of running threads, stack_save_td() returns EOPNOTSUPP.  If the
  target thread is running in user mode, stack_save_td() returns EBUSY.
  
  Reviewed by:	kib
  Reported by:	mjg, pho
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D23355

Modified:
  head/share/man/man9/stack.9
  head/sys/amd64/amd64/trap.c
  head/sys/arm/arm/stack_machdep.c
  head/sys/arm64/arm64/stack_machdep.c
  head/sys/i386/i386/trap.c
  head/sys/kern/kern_proc.c
  head/sys/kern/subr_kdb.c
  head/sys/kern/subr_sleepqueue.c
  head/sys/kern/tty_info.c
  head/sys/mips/mips/stack_machdep.c
  head/sys/powerpc/powerpc/stack_machdep.c
  head/sys/riscv/riscv/stack_machdep.c
  head/sys/sparc64/sparc64/stack_machdep.c
  head/sys/sys/stack.h
  head/sys/x86/include/apicvar.h
  head/sys/x86/include/stack.h
  head/sys/x86/x86/mp_x86.c
  head/sys/x86/x86/stack_machdep.c

Modified: head/share/man/man9/stack.9
==============================================================================
--- head/share/man/man9/stack.9	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/share/man/man9/stack.9	Fri Jan 31 15:43:33 2020	(r357334)
@@ -27,7 +27,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 6, 2017
+.Dd January 31, 2020
 .Dt STACK 9
 .Os
 .Sh NAME
@@ -65,10 +65,8 @@ In the kernel configuration file:
 .Fn stack_sbuf_print_ddb "struct sbuf sb*" "const struct stack *st"
 .Ft void
 .Fn stack_save "struct stack *st"
-.Ft void
-.Fn stack_save_td "struct stack *st" "struct thread *td"
 .Ft int
-.Fn stack_save_td_running "struct stack *st" "struct thread *td"
+.Fn stack_save_td "struct stack *st" "struct thread *td"
 .Sh DESCRIPTION
 The
 .Nm
@@ -93,18 +91,17 @@ argument is passed to
 Memory associated with a trace is freed by calling
 .Fn stack_destroy .
 .Pp
-A trace of the current kernel thread's call stack may be captured using
+A trace of the current thread's kernel call stack may be captured using
 .Fn stack_save .
 .Fn stack_save_td
-and
-.Fn stack_save_td_running
-can also be used to capture the stack of a caller-specified thread.
-Callers of these functions must own the thread lock of the specified thread.
+can be used to capture the kernel stack of a caller-specified thread.
+Callers of these functions must own the thread lock of the specified thread,
+and the thread's stack must not be swapped out.
 .Fn stack_save_td
-can capture the stack of a kernel thread that is not running or
-swapped out at the time of the call.
-.Fn stack_save_td_running
-can capture the stack of a running kernel thread.
+can capture the kernel stack of a running thread, though note that this is
+not implemented on all platforms.
+If the thread is running, the caller must also hold the process lock for the
+target thread.
 .Pp
 .Fn stack_print
 and
@@ -157,11 +154,11 @@ Otherwise the
 does not contain space to record additional frames, and a non-zero value is
 returned.
 .Pp
-.Fn stack_save_td_running
+.Fn stack_save_td
 returns 0 when the stack capture was successful and a non-zero error number
 otherwise.
 In particular,
-.Er EAGAIN
+.Er EBUSY
 is returned if the thread was running in user mode at the time that the
 capture was attempted, and
 .Er EOPNOTSUPP

Modified: head/sys/amd64/amd64/trap.c
==============================================================================
--- head/sys/amd64/amd64/trap.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/amd64/amd64/trap.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
 #include "opt_hwpmc_hooks.h"
 #include "opt_isa.h"
 #include "opt_kdb.h"
-#include "opt_stack.h"
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -226,11 +225,6 @@ trap(struct trapframe *frame)
 		 */
 		if (pmc_intr != NULL &&
 		    (*pmc_intr)(frame) != 0)
-			return;
-#endif
-
-#ifdef STACK
-		if (stack_nmi_handler(frame) != 0)
 			return;
 #endif
 	}

Modified: head/sys/arm/arm/stack_machdep.c
==============================================================================
--- head/sys/arm/arm/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/arm/arm/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -30,8 +30,11 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
+
 #include <machine/pcb.h>
 #include <machine/stack.h>
 
@@ -63,29 +66,23 @@ stack_save(struct stack *st)
 	stack_capture(st, &state);
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 	struct unwind_state state;
 
-	KASSERT(!TD_IS_SWAPPED(td), ("stack_save_td: swapped"));
-	KASSERT(!TD_IS_RUNNING(td), ("stack_save_td: running"));
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
 
+	if (TD_IS_RUNNING(td))
+		return (EOPNOTSUPP);
+
 	state.registers[FP] = td->td_pcb->pcb_regs.sf_r11;
 	state.registers[SP] = td->td_pcb->pcb_regs.sf_sp;
 	state.registers[LR] = td->td_pcb->pcb_regs.sf_lr;
 	state.registers[PC] = td->td_pcb->pcb_regs.sf_pc;
 
 	stack_capture(st, &state);
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	if (td == curthread) {
-		stack_save(st);
-		return (0);
-	}
-	return (EOPNOTSUPP);
+	return (0);
 }

Modified: head/sys/arm64/arm64/stack_machdep.c
==============================================================================
--- head/sys/arm64/arm64/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/arm64/arm64/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
 
@@ -55,28 +57,24 @@ stack_capture(struct stack *st, struct unwind_state *f
 	}
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 	struct unwind_state frame;
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+
 	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
+		return (EOPNOTSUPP);
 
 	frame.sp = td->td_pcb->pcb_sp;
 	frame.fp = td->td_pcb->pcb_x[29];
 	frame.pc = td->td_pcb->pcb_x[30];
 
 	stack_capture(st, &frame);
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	return (EOPNOTSUPP);
+	return (0);
 }
 
 void

Modified: head/sys/i386/i386/trap.c
==============================================================================
--- head/sys/i386/i386/trap.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/i386/i386/trap.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
 #include "opt_hwpmc_hooks.h"
 #include "opt_isa.h"
 #include "opt_kdb.h"
-#include "opt_stack.h"
 #include "opt_trap.h"
 
 #include <sys/param.h>
@@ -246,11 +245,6 @@ trap(struct trapframe *frame)
 		 */
 		if (pmc_intr != NULL &&
 		    (*pmc_intr)(frame) != 0)
-			return;
-#endif
-
-#ifdef STACK
-		if (stack_nmi_handler(frame) != 0)
 			return;
 #endif
 	}

Modified: head/sys/kern/kern_proc.c
==============================================================================
--- head/sys/kern/kern_proc.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/kern/kern_proc.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -2669,17 +2669,12 @@ sysctl_kern_proc_kstack(SYSCTL_HANDLER_ARGS)
 		    sizeof(kkstp->kkst_trace), SBUF_FIXEDLEN);
 		thread_lock(td);
 		kkstp->kkst_tid = td->td_tid;
-		if (TD_IS_SWAPPED(td)) {
+		if (TD_IS_SWAPPED(td))
 			kkstp->kkst_state = KKST_STATE_SWAPPED;
-		} else if (TD_IS_RUNNING(td)) {
-			if (stack_save_td_running(st, td) == 0)
-				kkstp->kkst_state = KKST_STATE_STACKOK;
-			else
-				kkstp->kkst_state = KKST_STATE_RUNNING;
-		} else {
+		else if (stack_save_td(st, td) == 0)
 			kkstp->kkst_state = KKST_STATE_STACKOK;
-			stack_save_td(st, td);
-		}
+		else
+			kkstp->kkst_state = KKST_STATE_RUNNING;
 		thread_unlock(td);
 		PROC_UNLOCK(p);
 		stack_sbuf_print(&sb, st);

Modified: head/sys/kern/subr_kdb.c
==============================================================================
--- head/sys/kern/subr_kdb.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/kern/subr_kdb.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -432,9 +432,8 @@ kdb_backtrace_thread(struct thread *td)
 		struct stack st;
 
 		printf("KDB: stack backtrace of thread %d:\n", td->td_tid);
-		stack_zero(&st);
-		stack_save_td(&st, td);
-		stack_print_ddb(&st);
+		if (stack_save_td(&st, td) == 0)
+			stack_print_ddb(&st);
 	}
 #endif
 }

Modified: head/sys/kern/subr_sleepqueue.c
==============================================================================
--- head/sys/kern/subr_sleepqueue.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/kern/subr_sleepqueue.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -1245,7 +1245,7 @@ sleepq_sbuf_print_stacks(struct sbuf *sb, const void *
 				goto loop_end;
 
 			/* Note the td_lock is equal to the sleepq_lock here. */
-			stack_save_td(st[stack_idx], td);
+			(void)stack_save_td(st[stack_idx], td);
 
 			sbuf_printf(td_infos[stack_idx], "%d: %s %p",
 			    td->td_tid, td->td_name, td);

Modified: head/sys/kern/tty_info.c
==============================================================================
--- head/sys/kern/tty_info.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/kern/tty_info.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -340,12 +340,8 @@ tty_info(struct tty *tp)
 	if (tty_info_kstacks) {
 		if (TD_IS_SWAPPED(td))
 			sterr = ENOENT;
-		else if (TD_IS_RUNNING(td))
-			sterr = stack_save_td_running(&stack, td);
-		else {
-			stack_save_td(&stack, td);
-			sterr = 0;
-		}
+		else
+			sterr = stack_save_td(&stack, td);
 	}
 #endif
 	thread_unlock(td);

Modified: head/sys/mips/mips/stack_machdep.c
==============================================================================
--- head/sys/mips/mips/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/mips/mips/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -29,9 +29,10 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include <sys/types.h>
-#include <sys/systm.h>
 #include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
 
@@ -127,26 +128,22 @@ done:
 	return;
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 	u_register_t pc, sp;
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+
 	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
+		return (EOPNOTSUPP);
 
 	pc = td->td_pcb->pcb_regs.pc;
 	sp = td->td_pcb->pcb_regs.sp;
 	stack_capture(st, pc, sp);
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	return (EOPNOTSUPP);
+	return (0);
 }
 
 void

Modified: head/sys/powerpc/powerpc/stack_machdep.c
==============================================================================
--- head/sys/powerpc/powerpc/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/powerpc/powerpc/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -30,6 +30,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
 #include <sys/systm.h>
@@ -86,25 +88,21 @@ stack_capture(struct stack *st, vm_offset_t frame)
 	}
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 	vm_offset_t frame;
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+
 	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
+		return (EOPNOTSUPP);
 
 	frame = td->td_pcb->pcb_sp;
 	stack_capture(st, frame);
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	return (EOPNOTSUPP);
+	return (0);
 }
 
 void

Modified: head/sys/riscv/riscv/stack_machdep.c
==============================================================================
--- head/sys/riscv/riscv/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/riscv/riscv/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
 
@@ -60,28 +62,24 @@ stack_capture(struct stack *st, struct unwind_state *f
 	}
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 	struct unwind_state frame;
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+
 	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
+		return (EOPNOTSUPP);
 
 	frame.sp = td->td_pcb->pcb_sp;
 	frame.fp = td->td_pcb->pcb_s[0];
 	frame.pc = td->td_pcb->pcb_ra;
 
 	stack_capture(st, &frame);
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	return (EOPNOTSUPP);
+	return (0);
 }
 
 void

Modified: head/sys/sparc64/sparc64/stack_machdep.c
==============================================================================
--- head/sys/sparc64/sparc64/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/sparc64/sparc64/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$");
 #include "opt_kstack_pages.h"
 
 #include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/proc.h>
 #include <sys/stack.h>
 #include <sys/systm.h>
@@ -72,23 +74,19 @@ stack_capture(struct stack *st, struct frame *frame)
 	}
 }
 
-void
+int
 stack_save_td(struct stack *st, struct thread *td)
 {
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
+	THREAD_LOCK_ASSERT(td, MA_OWNED);
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+
 	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
+		return (EOPNOTSUPP);
 
 	stack_capture(st, (struct frame *)(td->td_pcb->pcb_sp + SPOFF));
-}
-
-int
-stack_save_td_running(struct stack *st, struct thread *td)
-{
-
-	return (EOPNOTSUPP);
+	return (0);
 }
 
 void

Modified: head/sys/sys/stack.h
==============================================================================
--- head/sys/sys/stack.h	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/sys/stack.h	Fri Jan 31 15:43:33 2020	(r357334)
@@ -67,7 +67,6 @@ void		 stack_ktr(u_int, const char *, int, const struc
 /* MD Routines. */
 struct thread;
 void		 stack_save(struct stack *);
-void		 stack_save_td(struct stack *, struct thread *);
-int		 stack_save_td_running(struct stack *, struct thread *);
+int		 stack_save_td(struct stack *, struct thread *);
 
 #endif

Modified: head/sys/x86/include/apicvar.h
==============================================================================
--- head/sys/x86/include/apicvar.h	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/x86/include/apicvar.h	Fri Jan 31 15:43:33 2020	(r357334)
@@ -123,20 +123,20 @@
 #define	IPI_AST		0 	/* Generate software trap. */
 #define IPI_PREEMPT     1
 #define IPI_HARDCLOCK   2
-#define IPI_BITMAP_LAST IPI_HARDCLOCK
+#define	IPI_TRACE	3	/* Collect stack trace. */
+#define	IPI_BITMAP_LAST IPI_TRACE
 #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
 
 #define	IPI_STOP	(APIC_IPI_INTS + 6)	/* Stop CPU until restarted. */
 #define	IPI_SUSPEND	(APIC_IPI_INTS + 7)	/* Suspend CPU until restarted. */
 #define	IPI_DYN_FIRST	(APIC_IPI_INTS + 8)
-#define	IPI_DYN_LAST	(253)			/* IPIs allocated at runtime */
+#define	IPI_DYN_LAST	(254)			/* IPIs allocated at runtime */
 
 /*
  * IPI_STOP_HARD does not need to occupy a slot in the IPI vector space since
  * it is delivered using an NMI anyways.
  */
-#define	IPI_NMI_FIRST	254
-#define	IPI_TRACE	254			/* Interrupt for tracing. */
+#define	IPI_NMI_FIRST	255
 #define	IPI_STOP_HARD	255			/* Stop CPU with a NMI. */
 
 /*

Modified: head/sys/x86/include/stack.h
==============================================================================
--- head/sys/x86/include/stack.h	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/x86/include/stack.h	Fri Jan 31 15:43:33 2020	(r357334)
@@ -55,7 +55,7 @@ struct i386_frame {
 #endif /* __amd64__ */
 
 #ifdef _KERNEL
-int	stack_nmi_handler(struct trapframe *);
+void	stack_capture_intr(void);
 #endif
 
 #endif /* !_X86_STACK_H */

Modified: head/sys/x86/x86/mp_x86.c
==============================================================================
--- head/sys/x86/x86/mp_x86.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/x86/x86/mp_x86.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -31,10 +31,12 @@ __FBSDID("$FreeBSD$");
 #include "opt_apic.h"
 #endif
 #include "opt_cpu.h"
+#include "opt_ddb.h"
 #include "opt_kstack_pages.h"
 #include "opt_pmap.h"
 #include "opt_sched.h"
 #include "opt_smp.h"
+#include "opt_stack.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -75,6 +77,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/psl.h>
 #include <machine/smp.h>
 #include <machine/specialreg.h>
+#include <machine/stack.h>
 #include <x86/ucode.h>
 
 static MALLOC_DEFINE(M_CPUS, "cpus", "CPU items");
@@ -1284,6 +1287,10 @@ ipi_bitmap_handler(struct trapframe frame)
 	td->td_intr_nesting_level++;
 	oldframe = td->td_intr_frame;
 	td->td_intr_frame = &frame;
+#if defined(STACK) || defined(DDB)
+	if (ipi_bitmap & (1 << IPI_TRACE))
+		stack_capture_intr();
+#endif
 	if (ipi_bitmap & (1 << IPI_PREEMPT)) {
 #ifdef COUNT_IPIS
 		(*ipi_preempt_counts[cpu])++;

Modified: head/sys/x86/x86/stack_machdep.c
==============================================================================
--- head/sys/x86/x86/stack_machdep.c	Fri Jan 31 13:18:25 2020	(r357333)
+++ head/sys/x86/x86/stack_machdep.c	Fri Jan 31 15:43:33 2020	(r357334)
@@ -63,15 +63,12 @@ typedef struct i386_frame *x86_frame_t;
 typedef struct amd64_frame *x86_frame_t;
 #endif
 
-#ifdef STACK
-static struct stack *nmi_stack;
-static volatile struct thread *nmi_pending;
-
 #ifdef SMP
-static struct mtx nmi_lock;
-MTX_SYSINIT(nmi_lock, &nmi_lock, "stack_nmi", MTX_SPIN);
+static struct stack *stack_intr_stack;
+static struct thread *stack_intr_td;
+static struct mtx intr_lock;
+MTX_SYSINIT(intr_lock, &intr_lock, "stack intr", MTX_DEF);
 #endif
-#endif
 
 static void
 stack_capture(struct thread *td, struct stack *st, register_t fp)
@@ -97,74 +94,74 @@ stack_capture(struct thread *td, struct stack *st, reg
 	}
 }
 
-int
-stack_nmi_handler(struct trapframe *tf)
-{
-
-#ifdef STACK
-	/* Don't consume an NMI that wasn't meant for us. */
-	if (nmi_stack == NULL || curthread != nmi_pending)
-		return (0);
-
-	if (!TRAPF_USERMODE(tf) && (TF_FLAGS(tf) & PSL_I) != 0)
-		stack_capture(curthread, nmi_stack, TF_FP(tf));
-	else
-		/* We were running in usermode or had interrupts disabled. */
-		nmi_stack->depth = 0;
-
-	atomic_store_rel_ptr((long *)&nmi_pending, (long)NULL);
-	return (1);
-#else
-	return (0);
-#endif
-}
-
+#ifdef SMP
 void
-stack_save_td(struct stack *st, struct thread *td)
+stack_capture_intr(void)
 {
+	struct thread *td;
 
-	if (TD_IS_SWAPPED(td))
-		panic("stack_save_td: swapped");
-	if (TD_IS_RUNNING(td))
-		panic("stack_save_td: running");
-
-	stack_capture(td, st, PCB_FP(td->td_pcb));
+	td = curthread;
+	stack_capture(td, stack_intr_stack, TF_FP(td->td_intr_frame));
+	atomic_store_rel_ptr((void *)&stack_intr_td, (uintptr_t)td);
 }
+#endif
 
 int
-stack_save_td_running(struct stack *st, struct thread *td)
+stack_save_td(struct stack *st, struct thread *td)
 {
+	int cpuid, error;
+	bool done;
 
-#ifdef STACK
 	THREAD_LOCK_ASSERT(td, MA_OWNED);
-	MPASS(TD_IS_RUNNING(td));
+	KASSERT(!TD_IS_SWAPPED(td),
+	    ("stack_save_td: thread %p is swapped", td));
+	if (TD_IS_RUNNING(td) && td != curthread)
+		PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
 
 	if (td == curthread) {
 		stack_save(st);
 		return (0);
 	}
 
+	for (done = false, error = 0; !done;) {
+		if (!TD_IS_RUNNING(td)) {
+			/*
+			 * The thread will not start running so long as we hold
+			 * its lock.
+			 */
+			stack_capture(td, st, PCB_FP(td->td_pcb));
+			error = 0;
+			break;
+		}
+
 #ifdef SMP
-	mtx_lock_spin(&nmi_lock);
+		thread_unlock(td);
+		cpuid = atomic_load_int(&td->td_oncpu);
+		if (cpuid == NOCPU) {
+			cpu_spinwait();
+		} else {
+			mtx_lock(&intr_lock);
+			stack_intr_td = NULL;
+			stack_intr_stack = st;
+			ipi_cpu(cpuid, IPI_TRACE);
+			while (atomic_load_acq_ptr((void *)&stack_intr_td) ==
+			    (uintptr_t)NULL)
+				cpu_spinwait();
+			if (stack_intr_td == td) {
+				done = true;
+				error = st->depth > 0 ? 0 : EBUSY;
+			}
+			stack_intr_td = NULL;
+			mtx_unlock(&intr_lock);
+		}
+		thread_lock(td);
+#else
+		(void)cpuid;
+		KASSERT(0, ("%s: multiple running threads", __func__));
+#endif
+	}
 
-	nmi_stack = st;
-	nmi_pending = td;
-	ipi_cpu(td->td_oncpu, IPI_TRACE);
-	while ((void *)atomic_load_acq_ptr((long *)&nmi_pending) != NULL)
-		cpu_spinwait();
-	nmi_stack = NULL;
-
-	mtx_unlock_spin(&nmi_lock);
-
-	if (st->depth == 0)
-		return (EAGAIN);
-#else /* !SMP */
-	KASSERT(0, ("curthread isn't running"));
-#endif /* SMP */
-	return (0);
-#else /* !STACK */
-	return (EOPNOTSUPP);
-#endif /* STACK */
+	return (error);
 }
 
 void


More information about the svn-src-head mailing list