Re: another subtle signals issue

Linus Torvalds (torvalds@transmeta.com)
Wed, 12 Feb 2003 12:12:13 -0800 (PST)


Btw, Roland, instead of your previous patch I would prefer something that
just makes "sig_ignored()" test the state of the signal better. Ie
something like the appended.

This should bring it much closer to the old code, which got this _right_.
For example, a signal that is blocked is _never_ ignored, since even if
the handler is SIG_IGN right now, it may not be by the time it is
unblocked.

I bet the blocked case accounts for some of the new test failures, while
the (SIG_DFL && sig_kernel_ignore(sig)) case will account for a few more.
In general I _think_ this should get us pretty much back to the old
behaviour.

At least this fixes the pipe write() / SIGWINCH testcase for me.

Linus

---
===== kernel/signal.c 1.69 vs edited =====
--- 1.69/kernel/signal.c	Tue Feb 11 17:33:52 2003
+++ edited/kernel/signal.c	Wed Feb 12 12:03:28 2003
@@ -141,14 +141,34 @@
 	(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) &&	\
 	 ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
 
-#define sig_ignored(t, signr) \
-	(!((t)->ptrace & PT_PTRACED) && \
-	 (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_IGN)
-
 #define sig_fatal(t, signr) \
 	(!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
 	 (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
 
+static inline int sig_ignored(struct task_struct *t, int sig)
+{
+	void * handler;
+
+	/*
+	 * Tracers always want to know about signals..
+	 */
+	if (t->ptrace & PT_PTRACED)
+		return 0;
+
+	/*
+	 * Blocked signals are never ignored, since the
+	 * signal handler may change by the time it is
+	 * unblocked.
+	 */
+	if (sigismember(&t->blocked, sig))
+		return 0;
+
+	/* Is it explicitly or implicitly ignored? */
+	handler = t->sighand->action[sig-1].sa.sa_handler;
+	return   handler == SIG_IGN ||
+		(handler == SIG_DFL && sig_kernel_ignore(sig));
+}
+
 /*
  * Re-calculate pending state from the set of locally pending
  * signals, globally pending signals, and blocked signals.
@@ -642,7 +662,7 @@
 			 * TIF_SIGPENDING
 			 */
 			state = TASK_STOPPED;
-			if (!sigismember(&t->blocked, SIGCONT)) {
+			if (sig_user_defined(t, SIGCONT) && !sigismember(&t->blocked, SIGCONT)) {
 				set_tsk_thread_flag(t, TIF_SIGPENDING);
 				state |= TASK_INTERRUPTIBLE;
 			}

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/