git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] fetch: ignore SIGPIPE during network operation

From
Jeff King <peff@peff.net>
Date
Mar 3, 2019, 16:58 UTC
Message-ID
<20190303165843.GB23755@sigill.intra.peff.net>
In-Reply-To
<20190303165447.GA31116@sigill.intra.peff.net>

The default SIGPIPE behavior can be useful for a command that generates a lot of output: if the receiver of our output goes away, we'll be notified asynchronously to stop generating it (typically by killing the program).

But for a command like fetch, which is primarily concerned with receiving data and writing it to disk, an unexpected SIGPIPE can be awkward. We're already checking the return value of all of our write() calls, and dying due to the signal takes away our chance to gracefully handle the error.

On Linux, we wouldn't generally see SIGPIPE at all during fetch. If the other side of the network connection hangs up, we'll see ECONNRESET. But on OS X, we get a SIGPIPE, and the process is killed. This causes t5570 to racily fail, as we sometimes die by signal (instead of the expected die() call) when the server side hangs up.

Let's ignore SIGPIPE during the network portion of the fetch, which will cause our write() to return EPIPE, giving us consistent behavior across platforms.

This fixes the test flakiness, but note that it stops short of fixing the larger problem. The server side hit a fatal error, sent us an "ERR" packet, and then hung up. We notice the failure because we're trying to write to a closed socket. But by dying immediately, we never actually read the ERR packet and report its content to the user. This is a (racy) problem on all platforms. So this patch lays the groundwork from which that problem might be fixed consistently, but it doesn't actually fix it.

Note the placement of the SIGPIPE handling. The absolute minimal change would be to ignore SIGPIPE only when we're writing. But twiddling the signal handler for each write call is inefficient and maintenance burden. On the opposite end of the spectrum, we could simply declare that fetch does not need SIGPIPE handling, since it doesn't generate a lot of output, and we could just ignore it at the start of cmd_fetch().

This patch takes a middle ground. It ignores SIGPIPE during the network operation (which is admittedly most of the program, since the actual network operations are all done under the hood by the transport code). So it's still pretty coarse.

Signed-off-by: Jeff King <peff@peff.net>
---
I had a hard time trying to write the last two paragraphs. I think the
placement here really is not significantly different than just ignoring
SIGPIPE for the entirety of cmd_fetch(). I kind of like your suggestion
elsewhere in the thread to just teach the git wrapper an IGNORE_SIGPIPE
flag.
 builtin/fetch.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b620fd54b4..4ba63d5ac6 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1556,7 +1556,9 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 
 	sigchain_push_common(unlock_pack_on_signal);
 	atexit(unlock_pack);
+	sigchain_push(SIGPIPE, SIG_IGN);
 	exit_code = do_fetch(gtransport, &rs);
+	sigchain_pop(SIGPIPE);
 	refspec_clear(&rs);
 	transport_disconnect(gtransport);
 	gtransport = NULL;
-- 
2.21.0.675.g01c085a870
Previous: Jeff KingNext: Junio C Hamano
Message 17 of 21 in “t5570-git-daemon fails with SIGPIPE on OSX”
  1. SZEDER GáborAug 6, 2018
  2. SZEDER GáborAug 6, 2018
  3. Johannes SchindelinFeb 8, 2019
  4. SZEDER GáborFeb 8, 2019
  5. Jeff KingAug 14, 2018
  6. Jeff KingAug 14, 2018
  7. Johannes SchindelinFeb 8, 2019
  8. Johannes SchindelinFeb 8, 2019
  9. Jeff KingFeb 8, 2019
  10. Johannes SchindelinMar 1, 2019
  11. Jeff KingMar 1, 2019
  12. Johannes SchindelinMar 2, 2019
  13. Jeff KingMar 3, 2019
  14. 1/2 fetch: avoid calling write_or_die()Jeff King, Mar 3, 2019
  15. Duy NguyenMar 4, 2019
  16. Jeff KingMar 5, 2019
  17. 2/2 fetch: ignore SIGPIPE during network operationJeff King, Mar 3, 2019
  18. Junio C HamanoMar 4, 2019
  19. Jeff KingMar 5, 2019
  20. Junio C HamanoMar 3, 2019
  21. Johannes SchindelinMar 3, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.