Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144449445
D49678.id153532.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
4 KB
Referenced Files
None
Subscribers
None
D49678.id153532.diff
View Options
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
@@ -3286,6 +3286,49 @@
}
}
+static void
+sig_prep_first_dbg_stop(struct thread *td, struct proc *p, sigset_t *sp)
+{
+ MPASS(td->td_proc == p);
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED &&
+ (p->p_flag2 & P2_PTRACE_FSTP) != 0 &&
+ SIGISMEMBER(*sp, SIGSTOP)) {
+ /*
+ * If debugger just attached, always consume SIGSTOP
+ * from ptrace(PT_ATTACH) first, to execute the
+ * debugger attach ritual in order.
+ */
+ td->td_dbgflags |= TDB_FSTP;
+ SIGEMPTYSET(*sp);
+ SIGADDSET(*sp, SIGSTOP);
+ }
+}
+
+bool
+sig_handle_sigstop(struct thread *td)
+{
+ struct proc *p;
+ sigset_t sigpending;
+ enum sigstatus res;
+
+ p = td->td_proc;
+ PROC_LOCK(p);
+ sigpending = td->td_sigqueue.sq_signals;
+ SIGSETOR(sigpending, p->p_sigqueue.sq_signals);
+ sig_prep_first_dbg_stop(td, p, &sigpending);
+ if (SIGISMEMBER(sigpending, SIGSTOP)) {
+ mtx_lock(&p->p_sigacts->ps_mtx);
+ res = sigprocess(td, SIGSTOP);
+ mtx_unlock(&p->p_sigacts->ps_mtx);
+ } else {
+ res = SIGSTATUS_IGNORE;
+ }
+ PROC_UNLOCK(p);
+ return (res == SIGSTATUS_HANDLED);
+}
+
/*
* If the current process has received a signal (should be caught or cause
* termination, should interrupt current syscall), return the signal number.
@@ -3336,19 +3379,7 @@
}
}
- if ((p->p_flag & (P_TRACED | P_PPTRACE)) == P_TRACED &&
- (p->p_flag2 & P2_PTRACE_FSTP) != 0 &&
- SIGISMEMBER(sigpending, SIGSTOP)) {
- /*
- * If debugger just attached, always consume
- * SIGSTOP from ptrace(PT_ATTACH) first, to
- * execute the debugger attach ritual in
- * order.
- */
- td->td_dbgflags |= TDB_FSTP;
- SIGEMPTYSET(sigpending);
- SIGADDSET(sigpending, SIGSTOP);
- }
+ sig_prep_first_dbg_stop(td, p, &sigpending);
SIG_FOREACH(sig, &sigpending) {
switch (sigprocess(td, sig)) {
diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c
--- a/sys/kern/subr_sleepqueue.c
+++ b/sys/kern/subr_sleepqueue.c
@@ -659,6 +659,38 @@
sleepq_switch(wchan, pri);
}
+static bool
+sleepq_handle_sigstop(struct thread *td, const void *wchan)
+{
+ if ((td->td_flags & TDF_SBDRY) != 0 ||
+ !(td_ast_pending(td, TDA_SIG) ||
+ td_ast_pending(td, TDA_SUSPEND)))
+ return (false);
+ if (sig_handle_sigstop(td)) {
+//printf("STS td %p td_flags %#x p_flag %#x\n", td, td->td_flags, td->td_proc->p_flag);
+ /*
+ * The thread's interruptible sleep was aborted in
+ * order to suspend the process. Propagating the
+ * aborted sleep to the userspace boundary causes
+ * spurious EINTR returns from syscalls. Instead, we
+ * can handle signal processing here, noting that the
+ * place where interruptible non-boundary sleep is
+ * allowed is not much different from the userret()
+ * place.
+ *
+ * Note that we check the current process and thread
+ * states without locks. Also, only stops can be
+ * handled this way, since it is not safe to exit
+ * sleeping thread, because it might own resources
+ * needing destructors.
+ */
+ td->td_intrval = 0;
+ sleepq_lock(wchan);
+ return (true);
+ }
+ return (false);
+}
+
/*
* Block the current thread until it is awakened from its sleep queue
* or it is interrupted by a signal.
@@ -666,12 +698,19 @@
int
sleepq_wait_sig(const void *wchan, int pri)
{
- int rcatch;
+ struct thread *td;
+ int rcatch, rvals;
- rcatch = sleepq_catch_signals(wchan, pri);
- if (rcatch)
- return (rcatch);
- return (sleepq_check_signals());
+ td = curthread;
+ for (;;) {
+ rcatch = sleepq_catch_signals(wchan, pri);
+ if (rcatch != 0)
+ return (rcatch);
+ rvals = sleepq_check_signals();
+ if (rvals != 0 && sleepq_handle_sigstop(td, wchan))
+ continue;
+ return (rvals);
+ }
}
/*
@@ -699,17 +738,24 @@
int
sleepq_timedwait_sig(const void *wchan, int pri)
{
+ struct thread *td;
int rcatch, rvalt, rvals;
- rcatch = sleepq_catch_signals(wchan, pri);
- /* We must always call check_timeout() to clear sleeptimo. */
- rvalt = sleepq_check_timeout();
- rvals = sleepq_check_signals();
- if (rcatch)
- return (rcatch);
- if (rvals)
- return (rvals);
- return (rvalt);
+ td = curthread;
+ for (;;) {
+ rcatch = sleepq_catch_signals(wchan, pri);
+ /* We must always call check_timeout() to clear sleeptimo. */
+ rvalt = sleepq_check_timeout();
+ rvals = sleepq_check_signals();
+ if (rcatch != 0)
+ return (rcatch);
+ if (rvals != 0) {
+ if (sleepq_handle_sigstop(td, wchan))
+ continue;
+ return (rvals);
+ }
+ return (rvalt);
+ }
}
/*
diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h
--- a/sys/sys/signalvar.h
+++ b/sys/sys/signalvar.h
@@ -397,6 +397,7 @@
int sig_ast_checksusp(struct thread *td);
int sig_ast_needsigchk(struct thread *td);
void sig_drop_caught(struct proc *p);
+bool sig_handle_sigstop(struct thread *td);
void sigexit(struct thread *td, int sig) __dead2;
int sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **);
void sigfastblock_clear(struct thread *td);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 9, 12:20 PM (5 h, 6 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28577879
Default Alt Text
D49678.id153532.diff (4 KB)
Attached To
Mode
D49678: PT_ATTACH: do not interrupt interruptible sleeps
Attached
Detach File
Event Timeline
Log In to Comment