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-all
mailing list