All of lore.kernel.org
 help / color / mirror / Atom feed
* x86: SIGTRAP handling differences from 2.4 to 2.6
@ 2003-11-22 18:29 Daniel Barlow
  2003-11-22 19:02 ` Linus Torvalds
  0 siblings, 1 reply; 7+ messages in thread
From: Daniel Barlow @ 2003-11-22 18:29 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1866 bytes --]


There is a difference between 2.4 (tested in 2.4.23-rc2) and 2.6
(tested in 2.6.0-pre9) in the handling of "int 3" inside a SIGTRAP 
handler.

In 2.4, the handler appears to be recursively re-entered.  In 2.6 the
task is killed, along with any other tasks that share the same VM (I'm
not talking about thread groups; I have CLONE_PARENT and CLONE_VM set
but not CLONE_THREAD).

I'm not sure what the correct answer is, if indeed it's specified.
For contrast, in FreeBSD 5.1 I'm told that the signal handler runs to
completion and only on exit is it called again.  I would suggest that
this behaviour is probably more in keeping with the principle of least
astonishment, but maybe I astonish in atypical ways.

Nasty short brutish test program appended.  Change the #if 0 s to #if 1
if you want to see it lay waste to the other threads as well.

I'm reading linux-kernel through the archives, so a CC would be
appreciated if you want me to see answers fast.

---cut here---
#include <signal.h>
#if 0
#include <sched.h>
#include <linux/unistd.h>
#endif

void sigtrap_handler(int sig, struct siginfo *si, void * sc)
{
    printf("entered sigtrap handler, %d %x %x\n", sig,si,sc);
    sleep(2);
    asm("int3" : :);
    printf("leaving sigtrap handler, %d %x %x\n", sig,si,sc);
}

void do_stuff()
{
    pause();
}

main()
{
    struct sigaction sa;
    int i,j;
#if 0    
    i=clone(do_stuff,malloc(1024*1024)+1024*1024,
	    CLONE_VM|SIGCHLD|CLONE_PARENT,0);
    j=clone(do_stuff,malloc(1024*1024)+1024*1024,
	    CLONE_VM|SIGCHLD|CLONE_PARENT,0);
#endif
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction=sigtrap_handler;
    sa.sa_flags=SA_SIGINFO|SA_RESTART;
    sigaction(SIGTRAP,&sa,0);
    printf("go\n");
    sleep(2);
    asm("int3" : :);
    sleep(3600);
}
---cut here---


-dan

-- 

   http://web.metacircles.com/cirCLe_CD - Free Software Lisp/Linux distro

[-- Attachment #2: Type: application/pgp-signature, Size: 188 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-22 18:29 x86: SIGTRAP handling differences from 2.4 to 2.6 Daniel Barlow
@ 2003-11-22 19:02 ` Linus Torvalds
  2003-11-22 22:19   ` Paul Mackerras
  0 siblings, 1 reply; 7+ messages in thread
From: Linus Torvalds @ 2003-11-22 19:02 UTC (permalink / raw)
  To: Daniel Barlow; +Cc: linux-kernel


On Sat, 22 Nov 2003, Daniel Barlow wrote:
> 
> There is a difference between 2.4 (tested in 2.4.23-rc2) and 2.6
> (tested in 2.6.0-pre9) in the handling of "int 3" inside a SIGTRAP 
> handler.

Indeed.

The basic change is basically:

 - some signals are "thread synchronous", ie the thread _cannot_ continue 
   without taking them. Basically, any instruction fault does this, 
   since just returning would generally cause the instruction to just be 
   done again, and cause the same fault.

 - the difference between 2.4.x and 2.6.x is that in 2.4.x such a 
   thread-synchronous instruction will just blow through being blocked. So 
   even if you block them, they'll still happen. In 2.6.x, trying to block 
   a thread-synchronous signal will just cause the process to be killed 
   with that signal ("it can't be delivered, it can't be ignored, let's 
   just tell the user")

The reason for the change is that the 2.4.x behaviour ends up hiding bugs, 
and can cause surprising deadlocks in threaded programs. The 2.6.x 
behaviour is "You did something fundamentally wrong, just _die_ now".

> I'm not sure what the correct answer is, if indeed it's specified.
> For contrast, in FreeBSD 5.1 I'm told that the signal handler runs to
> completion and only on exit is it called again.

This works because "int 3" and "into" is what Intel calls a "trap" as
opposed to a "fault", and as such we _could_ delay handling the signal and
just continue along - when the exception happens, the CPU has already
executed the instruction, and the exception will return to _after_ the
instruction.

However, Linux will refuse to do that because delaying the SIGTRAP is 
pointless: 
 - you'd get it at the wrong spot, making it pointless
 - the wrong thread could get it if you just consider it a normal signal.

So Linux considers both "int 3" and "into" to be thread-synchronous, even 
though they are trivially recoverable. Which means that we have two 
options, and two options only: punch through the fact that the signal is 
blocked, or just say "that's wrong", and kill it.

NOTE NOTE NOTE!! If you actually _want_ the 2.4.x behaviour of recursive
signal invocation, you should just tell the kernel so: use the SA_NODEFER
flag to sigaction() to tell the kernel that you don't want to defer
recursive signals.

In short, the 2.6.x behaviour is the right one. 2.4.x was a strange
violation of the signal blocking, and I consider the FreeBSD behaviour to
be just bizarre.

And with 2.6.x, if you actually _want_ recursive signal handlers, you can 
do so (fairly portably, I might add - putting the SA_NODEFER flag there 
should make everybody do the same thing, even *BSD).

			Linus


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-22 19:02 ` Linus Torvalds
@ 2003-11-22 22:19   ` Paul Mackerras
  2003-11-22 22:40     ` Linus Torvalds
  0 siblings, 1 reply; 7+ messages in thread
From: Paul Mackerras @ 2003-11-22 22:19 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel

Linus Torvalds writes:

>    ... In 2.6.x, trying to block 
>    a thread-synchronous signal will just cause the process to be killed 
>    with that signal ("it can't be delivered, it can't be ignored, let's 
>    just tell the user")

Occasionally I have had a situation where the init process hits an
instruction fault (often because of a kernel bug, actually), such as
an access to a bad address.  On embedded platforms we sometimes get
the situation where init uses floating-point instructions but the CPU
doesn't have floating point and the kernel has been compiled without
FP emulation.  In these situations the system looks like it just
hangs, since init is doing nothing but take the same signal over and
over again.

In this case the signal would not actually be set to be blocked or
ignored but would end up being ignored because of the rule that "init
gets no signals it doesn't want".  I would prefer to see
thread-synchronous signals kill init if they are not handled, so that
at least we get a panic with a message that says what went wrong
rather than the system just spinning its wheels uselessly.

Regards,
Paul.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-22 22:19   ` Paul Mackerras
@ 2003-11-22 22:40     ` Linus Torvalds
  2003-11-23  6:21       ` H. Peter Anvin
  0 siblings, 1 reply; 7+ messages in thread
From: Linus Torvalds @ 2003-11-22 22:40 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linux-kernel


On Sun, 23 Nov 2003, Paul Mackerras wrote:
>
> In this case the signal would not actually be set to be blocked or
> ignored but would end up being ignored because of the rule that "init
> gets no signals it doesn't want".  I would prefer to see
> thread-synchronous signals kill init if they are not handled, so that
> at least we get a panic with a message that says what went wrong
> rather than the system just spinning its wheels uselessly.

Hmm.. Right now the init special case is in the signal _delivery_ path, 
which makes it hard to do something like that, since by then we no longer 
know/care who sent the signal.

We could move the special case into the send path instead (and then only
do it for "external signals" and not special case init at all for internal
signals).

Hmm.. Looking at the signal sending code, we actually do special-case 
"init" there already - but only for the "kill -1" case. If the test for 
"pid > 1" was moved into "group_send_sig_info()" instead, that would 
pretty much do it, I think.

Feel free to try something like that out. I'm not going to apply it right 
now, though ;)

		Linus


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-22 22:40     ` Linus Torvalds
@ 2003-11-23  6:21       ` H. Peter Anvin
  2003-11-23 17:59         ` Linus Torvalds
  0 siblings, 1 reply; 7+ messages in thread
From: H. Peter Anvin @ 2003-11-23  6:21 UTC (permalink / raw)
  To: linux-kernel

Followup to:  <Pine.LNX.4.44.0311221435090.2379-100000@home.osdl.org>
By author:    Linus Torvalds <torvalds@osdl.org>
In newsgroup: linux.dev.kernel
> 
> Hmm.. Looking at the signal sending code, we actually do special-case 
> "init" there already - but only for the "kill -1" case. If the test for 
> "pid > 1" was moved into "group_send_sig_info()" instead, that would 
> pretty much do it, I think.
> 

Okay... I'm going to ask the obvious dumb question:

Why do we bother special-casing init at all?

It seems the only things init can't ask the kernel to do already for
it is to block SIGSTOP and SIGKILL, and it seems that if you killed
(or stopped?) init you should just get the kernel panic.

If there is anything that should be special-cased, then perhaps it
should be that init should be allowed to block/catch/ignore
SIGSTOP/SIGKILL.  Perhaps that should be a capability?

	-hpa
-- 
<hpa@transmeta.com> at work, <hpa@zytor.com> in private!
If you send me mail in HTML format I will assume it's spam.
"Unix gives you enough rope to shoot yourself in the foot."
Architectures needed: ia64 m68k mips64 ppc ppc64 s390 s390x sh v850 x86-64

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-23  6:21       ` H. Peter Anvin
@ 2003-11-23 17:59         ` Linus Torvalds
  2003-11-24 23:57           ` jw schultz
  0 siblings, 1 reply; 7+ messages in thread
From: Linus Torvalds @ 2003-11-23 17:59 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: linux-kernel


On 22 Nov 2003, H. Peter Anvin wrote:
> > 
> > Hmm.. Looking at the signal sending code, we actually do special-case 
> > "init" there already - but only for the "kill -1" case. If the test for 
> > "pid > 1" was moved into "group_send_sig_info()" instead, that would 
> > pretty much do it, I think.
> > 
> 
> Okay... I'm going to ask the obvious dumb question:
> 
> Why do we bother special-casing init at all?

Because the kernel depends on it existing. "init" literally _is_ special 
from a kernel standpoint, because its' the "reaper of zombies" (and, may I 
add, that would be a great name for a rock band).

So without init, the kernel wouldn't have anybody to fall back on when a 
parent process dies, and would become very very unhappy. Historically it 
actually oopsed the kernel.

UNIX semantics literally _require_ that "getppid()" should return 1 if 
your parent dies, and that's "current->p_parent->tgid". So we have to have 
a parent with pid 1, and thus init really _is_ special.

Yeah, we could have _other_ special cases (we could create another process 
that is invisible and has pid 1), but the fact is, _some_ special case is 
required. It might as well be "you can't kill init".

		Linus


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: x86: SIGTRAP handling differences from 2.4 to 2.6
  2003-11-23 17:59         ` Linus Torvalds
@ 2003-11-24 23:57           ` jw schultz
  0 siblings, 0 replies; 7+ messages in thread
From: jw schultz @ 2003-11-24 23:57 UTC (permalink / raw)
  To: linux-kernel

On Sun, Nov 23, 2003 at 09:59:47AM -0800, Linus Torvalds wrote:
> 
> On 22 Nov 2003, H. Peter Anvin wrote:
> > 
> > Okay... I'm going to ask the obvious dumb question:
> > 
> > Why do we bother special-casing init at all?
> 
> Because the kernel depends on it existing. "init" literally _is_ special 
> from a kernel standpoint, because its' the "reaper of zombies" (and, may I 
> add, that would be a great name for a rock band).
> 
> So without init, the kernel wouldn't have anybody to fall back on when a 
> parent process dies, and would become very very unhappy. Historically it 
> actually oopsed the kernel.
> 
> UNIX semantics literally _require_ that "getppid()" should return 1 if 
> your parent dies, and that's "current->p_parent->tgid". So we have to have 
> a parent with pid 1, and thus init really _is_ special.
> 
> Yeah, we could have _other_ special cases (we could create another process 
> that is invisible and has pid 1), but the fact is, _some_ special case is 
> required. It might as well be "you can't kill init".

For a normal init where is pretty bullet resistant having it
unkillable makes sense.  If init were somehow to go
pathological the whole system is suspect.

On the other hand, there are some who run something besides
the usual init. In that case it might make sense to allow
init to respawn.  -- speculation only.

-- 
________________________________________________________________
	J.W. Schultz            Pegasystems Technologies
	email address:		jw@pegasys.ws

		Remember Cernan and Schmitt

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2003-11-24 23:57 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-11-22 18:29 x86: SIGTRAP handling differences from 2.4 to 2.6 Daniel Barlow
2003-11-22 19:02 ` Linus Torvalds
2003-11-22 22:19   ` Paul Mackerras
2003-11-22 22:40     ` Linus Torvalds
2003-11-23  6:21       ` H. Peter Anvin
2003-11-23 17:59         ` Linus Torvalds
2003-11-24 23:57           ` jw schultz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.