Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jonathan Nieder
Jeff King wrote:

 The write_or_die function will always die on an error,
 including EPIPE. However, it currently treats EPIPE
 specially by suppressing any error message, and by exiting
 with exit code 0.

 Suppressing the error message makes some sense; a pipe death
 may just be a sign that the other side is not interested in
 what we have to say. However, exiting with a successful
 error code is not a good idea, as write_or_die is frequently
 used in cases where we want to be careful about having
 written all of the output, and we may need to signal to our
 caller that we have done so (e.g., you would not want a push
 whose other end has hung up to report success).

 This distinction doesn't typically matter in git, because we
 do not ignore SIGPIPE in the first place. Which means that
 we will not get EPIPE, but instead will just die when we get
 a SIGPIPE. But it's possible for a default handler to be set
 by a parent process,

Not so much default as insane inherited, as in the example
of old versions of Python's subprocess.Popen.

I suspect this used exit(0) instead of raise(SIGPIPE) in the first
place to work around a bash bug (too much verbosity about SIGPIPE).
If any programs still have that kind of bug, I'd rather put pressure
on them to fix it by *not* working around it.  So the basic idea here
looks good to me.

[...]
 --- a/write_or_die.c
 +++ b/write_or_die.c
 @@ -1,5 +1,15 @@
  #include cache.h
  
 +static void check_pipe(int err)
 +{
 + if (err == EPIPE) {
 + signal(SIGPIPE, SIG_DFL);
 + raise(SIGPIPE);
 + /* Should never happen, but just in case... */
 + exit(141);

How about

die(BUG: another thread changed SIGPIPE handling behind my 
back!);

to make it easier to find and fix such problems?

Thanks,
Jonathan
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jeff King
On Wed, Feb 20, 2013 at 01:51:11PM -0800, Jonathan Nieder wrote:

  This distinction doesn't typically matter in git, because we
  do not ignore SIGPIPE in the first place. Which means that
  we will not get EPIPE, but instead will just die when we get
  a SIGPIPE. But it's possible for a default handler to be set
  by a parent process,
 
 Not so much default as insane inherited, as in the example
 of old versions of Python's subprocess.Popen.

It's possible that somebody could have a legitimate reason for doing so.
I just can't think of one. :)

 I suspect this used exit(0) instead of raise(SIGPIPE) in the first
 place to work around a bash bug (too much verbosity about SIGPIPE).
 If any programs still have that kind of bug, I'd rather put pressure
 on them to fix it by *not* working around it.  So the basic idea here
 looks good to me.

Yeah, if you look for old discussions on SIGPIPE in the git list, it is
mostly Linus complaining about the bash behavior, and this code does
date back to that era. The bash bug is long since fixed.

  +   if (err == EPIPE) {
  +   signal(SIGPIPE, SIG_DFL);
  +   raise(SIGPIPE);
  +   /* Should never happen, but just in case... */
  +   exit(141);
 
 How about
 
   die(BUG: another thread changed SIGPIPE handling behind my 
 back!);
 
 to make it easier to find and fix such problems?

You mean for the should never happen bit, not the first part, right? I
actually wonder if we should simply exit(141) in the first place. That
is shell exit-code for SIGPIPE death already (so it's what our
run_command would show us, and what anybody running us through shell
would see).

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jonathan Nieder
Jeff King wrote:
 On Wed, Feb 20, 2013 at 01:51:11PM -0800, Jonathan Nieder wrote:

 +   if (err == EPIPE) {
 +   signal(SIGPIPE, SIG_DFL);
 +   raise(SIGPIPE);
 +   /* Should never happen, but just in case... */
 +   exit(141);

 How about

  die(BUG: another thread changed SIGPIPE handling behind my 
 back!);

 to make it easier to find and fix such problems?

 You mean for the should never happen bit, not the first part, right? I
 actually wonder if we should simply exit(141) in the first place. That
 is shell exit-code for SIGPIPE death already (so it's what our
 run_command would show us, and what anybody running us through shell
 would see).

Yes, for the should never happen part.  Raising a signal is nice
because it means the wait()-ing process can see what happened by
checking WIFSIGNALED(status).

Jonathan
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jeff King
On Wed, Feb 20, 2013 at 02:01:14PM -0800, Jonathan Nieder wrote:

  How about
 
 die(BUG: another thread changed SIGPIPE handling behind my 
  back!);
 
  to make it easier to find and fix such problems?
 
  You mean for the should never happen bit, not the first part, right? I
  actually wonder if we should simply exit(141) in the first place. That
  is shell exit-code for SIGPIPE death already (so it's what our
  run_command would show us, and what anybody running us through shell
  would see).
 
 Yes, for the should never happen part.  Raising a signal is nice
 because it means the wait()-ing process can see what happened by
 checking WIFSIGNALED(status).

Right. My point is that only happens if there's no shell in the way. But
I guess it doesn't hurt to make the attempt to help the people using
wait() directly.

I don't mind adding a BUG:  message like you described, but we should
still try to exit(141) as the backup, since that is the shell-equivalent
code to the SIGPIPE signal death.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jonathan Nieder
Jeff King wrote:
 On Wed, Feb 20, 2013 at 02:01:14PM -0800, Jonathan Nieder wrote:

 How about

die(BUG: another thread changed SIGPIPE handling behind my 
 back!);

 to make it easier to find and fix such problems?

 You mean for the should never happen bit, not the first part, right? I
 actually wonder if we should simply exit(141) in the first place. That
 is shell exit-code for SIGPIPE death already (so it's what our
 run_command would show us, and what anybody running us through shell
 would see).

 Yes, for the should never happen part.
[...]
 I don't mind adding a BUG:  message like you described, but we should
 still try to exit(141) as the backup, since that is the shell-equivalent
 code to the SIGPIPE signal death.

If you want. :)

I think caring about graceful degradation of behavior in the case of
an assertion failure is overengineering, but it's mostly harmless.
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Jeff King
On Wed, Feb 20, 2013 at 02:06:37PM -0800, Jonathan Nieder wrote:

  I don't mind adding a BUG:  message like you described, but we should
  still try to exit(141) as the backup, since that is the shell-equivalent
  code to the SIGPIPE signal death.
 
 If you want. :)
 
 I think caring about graceful degradation of behavior in the case of
 an assertion failure is overengineering, but it's mostly harmless.

I am more concerned that the assertion is not oops, another thread is
doing something crazy, and it is a bug, but rather that there is some
weird platform where SIG_DFL does not kill the program under SIGPIPE.
That seems pretty crazy, though. I think I'd squash in something like
this:

diff --git a/write_or_die.c b/write_or_die.c
index b50f99a..abb64db 100644
--- a/write_or_die.c
+++ b/write_or_die.c
@@ -5,7 +5,9 @@ static void check_pipe(int err)
if (err == EPIPE) {
signal(SIGPIPE, SIG_DFL);
raise(SIGPIPE);
+
/* Should never happen, but just in case... */
+   error(BUG: SIGPIPE on SIG_DFL handler did not kill us.);
exit(141);
}
 }

which more directly reports the assertion that failed, and degrades
reasonably gracefully. Yeah, it's probably overengineering, but it's
easy enough to do.

-Peff
--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v3 08/19] write_or_die: raise SIGPIPE when we get EPIPE

2013-02-20 Thread Junio C Hamano
Jeff King p...@peff.net writes:

 I am more concerned that the assertion is not oops, another thread is
 doing something crazy, and it is a bug, but rather that there is some
 weird platform where SIG_DFL does not kill the program under SIGPIPE.
 That seems pretty crazy, though. I think I'd squash in something like
 this:

 diff --git a/write_or_die.c b/write_or_die.c
 index b50f99a..abb64db 100644
 --- a/write_or_die.c
 +++ b/write_or_die.c
 @@ -5,7 +5,9 @@ static void check_pipe(int err)
   if (err == EPIPE) {
   signal(SIGPIPE, SIG_DFL);
   raise(SIGPIPE);
 +
   /* Should never happen, but just in case... */
 + error(BUG: SIGPIPE on SIG_DFL handler did not kill us.);
   exit(141);
   }
  }

 which more directly reports the assertion that failed, and degrades
 reasonably gracefully. Yeah, it's probably overengineering, but it's
 easy enough to do.

Yeah, that sounds like a sensible thing to do, as it is cheap even
though we do not expect it to trigger.

--
To unsubscribe from this list: send the line unsubscribe git in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html