Subject: Re: Sane exit from a program on receipt of a signal
To: None <tech-userlevel@NetBSD.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-userlevel
Date: 07/26/2007 08:13:57
> Hm, before unusual SIGTSTP usages, we should discuss normal SIGTSTP
> usages.

> The most normal way to suspend a foreground job (aka process group)
> is this.

>  0. Send SIGTSTP to the process group, which do the default behavior.
>     (such as kill(-pgid, SIGTSTP))

The "most normal way" does not involve kill(2); the most normal way to
generate SIGTSTP is to type c_cc[VSUSP].

My point is that this already generates a signal to each process of the
process group,

> If the process group needs some work before suspension, [...]

Except here, we don't have "the process group" needing work; we have an
individual process needing work.

> the most foreground process of the process group

What is this?  Process group leader?  (What if the SIGTSTP-aware
process isn't the group leader?)  Process that happens to want to
handle SIGTSTP?  (What if there are multiple such in the process
group?)

> will do one from following.

>  1. Simulate tty SIGTSTP.  If the process wants to suspend, send SIGTSTP
>     to its own process group.
>     (such as kill(0, SIGTSTP))

This is correct if, and only if, no SIGTSTP has already been generated
to the process group.  An example might be vi's behaviour on receipt of
^Z, which vi uses as a suspend command regardless of the user's suspc.

>  2. Trap SIGTSTP, do something, reset signal hander and resend
>     SIGTSTP to itself.

Right.  This is the case under discussion.  And you said it yourself:
"to itself".  Not "to its entire process group".

> A SIGTSTP usage other than above is just a corner case or an
> accident.

Agreed.

> Since 1. is the most often the case that requires SIGTSTP handling,
> we need kill(0, SIGTSTP) anyway.

Only when a SIGTSTP to the group hasn't already been generated.
Occasionally this is what you want, as with the vi example above.  More
often it's not, as with curses's SIGTSTP code, which is invoked only
when a SIGTSTP has already been generated.

> The case 2. we can use either kill(getpid(), SIGTSTP) or kill(0, SIGTSTP).
> I'd recommend kill(0, SIGTSTP) here since
>  - we can share the same code with 1.,
>  - code is simpler,
>  - it behaves better (for users) in the corner cases.

I disagree.  Naïve users will notice the difference only when the extra
SIGTSTPs generated by kill-to-group calls make programs behave in ways
that make no intuitive sense (rare, since it requires non-idempotent
SIGTSTP handling, but certainly possible).

> OK, then, let's discuss the corner cases.

>> So?  Just because other software is broken is no reason for us to
>> write more broken software.  (I wasn't aware of this bug in curses;
>> it really ought to be fixed.  Thanks for pointing it out.)
> What is the benefit of ``fixing'' programs to be less safe to users?

How is it less safe?  I'd say the kill-to-group way is less safe,
because it risks sending other processes in the group multiple SIGTSTPs
when they should receive only one.

>>> Stopping only one process of a process group [...]
>> Right.  So?  As I wrote, if it was generated from the tty, it's
>> already been sent to the rest of the process group.  If it was
>> generated with kill(), then either it's already been sent to the
>> rest of the process group or it shouldn't be sent to the rest of the
>> process group.
> As you notice, it is not needed,

Right.

> but does no harm.

Wrong.  *Usually* it does no harm.  It does no harm precisely when all
affected processes have idempotent SIGTSTP handling.  This is the usual
case (SIGTSTP stops the process, and SIGTSTP to a stopped process is
ignored) but it certainly does not have to be so.

> So this is OK.

Disagree.  It is never necessary and occasionally harmful.  The only
case where it is a good thing is when someone specifically sends a
SIGTSTP to just one process but expects it to affect the entire process
group.  This isn't the way default SIGTSTP handling works, so any such
attempt is broken in general; I prefer this routine behave the same way
as default SIGTSTP handling to the extent possible, which means *not*
resending to other processes.

>> Yes...if the process happens to be stopped at that point.  Which it
>> may not be, for any of various reasons.
> I admit it is a waste, but better than leaving terminal unusable when
> the SIGTSTP is sent to this process specifically.

Disagree.  You don't - can't - know that it will result in "leaving
[the] terminal unusable".  "Unix does not stop you from doing stupid
things, because that would also stop you from doing clever things."

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B