Skip to content

Commit a27341c

Browse files
committed
Prioritize synchronous signals over 'normal' signals
This makes sure that we pick the synchronous signals caused by a processor fault over any pending regular asynchronous signals sent to use by [t]kill(). This is not strictly required semantics, but it makes it _much_ easier for programs like Wine that expect to find the fault information in the signal stack. Without this, if a non-synchronous signal gets picked first, the delayed asynchronous signal will have its signal context pointing to the new signal invocation, rather than the instruction that caused the SIGSEGV or SIGBUS in the first place. This is not all that pretty, and we're discussing making the synchronous signals more explicit rather than have these kinds of implicit preferences of SIGSEGV and friends. See for example http://bugzilla.kernel.org/show_bug.cgi?id=15395 for some of the discussion. But in the meantime this is a simple and fairly straightforward work-around, and the whole if (x & Y) x &= Y; thing can be compiled into (and gcc does do it) just three instructions: movq %rdx, %rax andl $Y, %eax cmovne %rax, %rdx so it is at least a simple solution to a subtle issue. Reported-and-tested-by: Pavel Vilim <wylda@volny.cz> Acked-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent eaa5eec commit a27341c

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

kernel/signal.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -159,33 +159,50 @@ void recalc_sigpending(void)
159159

160160
/* Given the mask, find the first available signal that should be serviced. */
161161

162+
#define SYNCHRONOUS_MASK \
163+
(sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \
164+
sigmask(SIGTRAP) | sigmask(SIGFPE))
165+
162166
int next_signal(struct sigpending *pending, sigset_t *mask)
163167
{
164168
unsigned long i, *s, *m, x;
165169
int sig = 0;
166170

167171
s = pending->signal.sig;
168172
m = mask->sig;
173+
174+
/*
175+
* Handle the first word specially: it contains the
176+
* synchronous signals that need to be dequeued first.
177+
*/
178+
x = *s &~ *m;
179+
if (x) {
180+
if (x & SYNCHRONOUS_MASK)
181+
x &= SYNCHRONOUS_MASK;
182+
sig = ffz(~x) + 1;
183+
return sig;
184+
}
185+
169186
switch (_NSIG_WORDS) {
170187
default:
171-
for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m)
172-
if ((x = *s &~ *m) != 0) {
173-
sig = ffz(~x) + i*_NSIG_BPW + 1;
174-
break;
175-
}
188+
for (i = 1; i < _NSIG_WORDS; ++i) {
189+
x = *++s &~ *++m;
190+
if (!x)
191+
continue;
192+
sig = ffz(~x) + i*_NSIG_BPW + 1;
193+
break;
194+
}
176195
break;
177196

178-
case 2: if ((x = s[0] &~ m[0]) != 0)
179-
sig = 1;
180-
else if ((x = s[1] &~ m[1]) != 0)
181-
sig = _NSIG_BPW + 1;
182-
else
197+
case 2:
198+
x = s[1] &~ m[1];
199+
if (!x)
183200
break;
184-
sig += ffz(~x);
201+
sig = ffz(~x) + _NSIG_BPW + 1;
185202
break;
186203

187-
case 1: if ((x = *s &~ *m) != 0)
188-
sig = ffz(~x) + 1;
204+
case 1:
205+
/* Nothing to do */
189206
break;
190207
}
191208

0 commit comments

Comments
 (0)