From owner-svn-src-head@freebsd.org Fri Jan 31 15:43:37 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 8EE5E2433B4; Fri, 31 Jan 2020 15:43:37 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 488M2K44Gqz3HZk; Fri, 31 Jan 2020 15:43:37 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 86BEA1847F; Fri, 31 Jan 2020 15:43:37 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 00VFhbMg016815; Fri, 31 Jan 2020 15:43:37 GMT (envelope-from markj@FreeBSD.org) Received: (from markj@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 00VFhXak016797; Fri, 31 Jan 2020 15:43:33 GMT (envelope-from markj@FreeBSD.org) Message-Id: <202001311543.00VFhXak016797@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: markj set sender to markj@FreeBSD.org using -f From: Mark Johnston Date: Fri, 31 Jan 2020 15:43:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: 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... X-SVN-Group: head X-SVN-Commit-Author: markj X-SVN-Commit-Paths: 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/x86/include sys/x86/x86 X-SVN-Commit-Revision: 357334 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 31 Jan 2020 15:43:37 -0000 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 #include @@ -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 #include +#include +#include #include #include + #include #include @@ -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 #include +#include +#include #include #include @@ -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 @@ -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 __FBSDID("$FreeBSD$"); -#include -#include #include +#include +#include +#include #include #include @@ -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 +#include +#include #include #include #include @@ -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 #include +#include +#include #include #include @@ -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 +#include +#include #include #include #include @@ -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 #include @@ -75,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include 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