diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -115,6 +115,8 @@ static struct thread *sigtd(struct proc *p, int sig, bool fast_sigblock); static void sigqueue_start(void); static void sigfastblock_setpend(struct thread *td, bool resched); +static void sig_handle_first_stop(struct thread *td, struct proc *p, + int sig, bool ext); static uma_zone_t ksiginfo_zone = NULL; const struct filterops sig_filtops = { @@ -172,6 +174,11 @@ "Discard ignored signals on delivery, otherwise queue them to " "the target queue"); +static bool sigstop_transparent = true; +SYSCTL_BOOL(_debug, OID_AUTO, sigstop_transparent, CTLFLAG_RWTUN, + &sigstop_transparent, 0, + "hide wakes from SIGSTOP on interruptible sleeps"); + SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); /* @@ -2363,6 +2370,16 @@ if (prop & SIGPROP_CONT) sigqueue_delete_stopmask_proc(p); else if (prop & SIGPROP_STOP) { + if (sigstop_transparent && + (p->p_flag & P_TRACED) != 0 && + (p->p_flag2 & P2_PTRACE_FSTP) != 0) { + td->td_dbgflags |= TDB_FSTP; + PROC_SLOCK(p); + sig_handle_first_stop(td, p, sig, true); + PROC_SUNLOCK(p); + return (0); + } + /* * If sending a tty stop signal to a member of an orphaned * process group, discard the signal here if the action @@ -2820,6 +2837,29 @@ } } +static void +sig_handle_first_stop(struct thread *td, struct proc *p, int sig, bool ext) +{ + if ((td->td_dbgflags & TDB_FSTP) == 0 && + ((p->p_flag2 & P2_PTRACE_FSTP) != 0 || + p->p_xthread != NULL)) + return; + + p->p_xsig = sig; + p->p_xthread = td; + + /* + * If we are on sleepqueue already, let sleepqueue + * code decide if it needs to go sleep after attach. + */ + if (ext || td->td_wchan == NULL) + td->td_dbgflags &= ~TDB_FSTP; + + p->p_flag2 &= ~P2_PTRACE_FSTP; + p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE; + sig_suspend_threads(td, p); +} + /* * Stop the process for an event deemed interesting to the debugger. If si is * non-NULL, this is a signal exchange; the new signal requested by the @@ -2880,24 +2920,8 @@ * already set p_xthread, the current thread will get * a chance to report itself upon the next iteration. */ - if ((td->td_dbgflags & TDB_FSTP) != 0 || - ((p->p_flag2 & P2_PTRACE_FSTP) == 0 && - p->p_xthread == NULL)) { - p->p_xsig = sig; - p->p_xthread = td; + sig_handle_first_stop(td, p, sig, false); - /* - * If we are on sleepqueue already, - * let sleepqueue code decide if it - * needs to go sleep after attach. - */ - if (td->td_wchan == NULL) - td->td_dbgflags &= ~TDB_FSTP; - - p->p_flag2 &= ~P2_PTRACE_FSTP; - p->p_flag |= P_STOPPED_SIG | P_STOPPED_TRACE; - sig_suspend_threads(td, p); - } if ((td->td_dbgflags & TDB_STOPATFORK) != 0) { td->td_dbgflags &= ~TDB_STOPATFORK; } @@ -3336,7 +3360,8 @@ } } - if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED && + if (!sigstop_transparent && + (p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED && (p->p_flag2 & P2_PTRACE_FSTP) != 0 && SIGISMEMBER(sigpending, SIGSTOP)) { /* diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -4378,7 +4378,10 @@ exit(0); } - attach_child(fpid); + wpid = waitpid(fpid, &status, 0); + REQUIRE_EQ(wpid, fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); pscr.pscr_syscall = SYS_getpid; pscr.pscr_nargs = 0;