{"thread":{"id":"42079","subject":"[PATCH 0/5] fix deadlock in git-push","startedAt":"2016-04-19T22:39:46Z","lastAt":"2016-04-21T05:18:57Z","messageCount":10,"participants":["Jeff King","Junio C Hamano","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"283864","messageId":"20160419223945.GA18055@sigill.intra.peff.net","threadId":"42079","inReplyTo":null,"subject":"[PATCH 0/5] fix deadlock in git-push","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:39:46Z","receivedAt":"2016-04-19T22:39:46Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"I ran across a deadlock today while pushing from a corrupted repository\nwhere pack-objects fails. Obviously I don't expect this to succeed, but\nit should not hang indefinitely.\n\nThe first patch below fixes the deadlock. Unfortunately, it turns it\ninto a likely SIGPIPE death. Which is an improvement, but not ideal.\n\nPatches 2 and 3 address that by fixing the way we handle SIGPIPE in\nasync threads.\n\nPatches 4 and 5 are cleanups to earlier topics that are enabled by the\nnew SIGPIPE handling.\n\n  [1/5]: send-pack: close demux pipe before finishing async process\n  [2/5]: run-command: teach async threads to ignore SIGPIPE\n  [3/5]: send-pack: isolate sigpipe in demuxer thread\n  [4/5]: fetch-pack: isolate sigpipe in demuxer thread\n  [5/5]: t5504: drop sigpipe=ok from push tests\n\nI confirmed that after this series we still pass the stress test I\noutlined in\n\n  http://article.gmane.org/gmane.comp.version-control.git/287176\n\nSo hopefully I haven't made anything worse (and that the tightening in\n5/5 isn't just bringing back some test flakiness).\n\n-Peff\n"},{"id":"283865","messageId":"20160419224517.GA18255@sigill.intra.peff.net","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"[PATCH 1/5] send-pack: close demux pipe before finishing async process","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:45:17Z","receivedAt":"2016-04-19T22:45:17Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"This fixes a deadlock on the client side when pushing a\nlarge number of refs from a corrupted repo.  There's a\nreproduction script below, but let's start with a\nhuman-readable explanation.\n\nThe client side of a push goes something like this:\n\n  1. Start an async process to demux sideband coming from\n     the server.\n\n  2. Run pack-objects to send the actual pack, and wait for\n     its status via finish_command().\n\n  3. If pack-objects failed, abort immediately.\n\n  4. If pack-objects succeeded, read the per-ref status from\n     the server, which is actually coming over a pipe from\n     the demux process started in step 1.\n\nWe run finish_async() to wait for and clean up the demux\nprocess in two places. In step 3, if we see an error, we\nwant it to end early. And after step 4, it should be done\nwriting any data and we are just cleaning it up.\n\nLet's focus on the error case first. We hand the output\ndescriptor to the server over to pack-objects. So by the\ntime it has returned an error to us, it has closed the\ndescriptor and the server has gotten EOF. The server will\nmark all refs as failed with \"unpacker error\" and send us\nback the status for each (followed by EOF).\n\nThis status goes to the demuxer thread, which relays it over\na pipe to the main thread. But the main thread never even\ntries reading the status. It's trying to bail because of the\npack-objects error, and is waiting for the demuxer thread to\nfinish. If there are a small number of refs, that's OK; the\ndemuxer thread writes into the pipe buffer, sees EOF from\nthe server, and quits. But if there are a large number of\nrefs, it may block on write() back to the main thread,\nleading to a deadlock (the main thread is waiting for the\ndemuxer to finish, the demuxer is waiting for the main\nthread to read).\n\nWe can break this deadlock by closing the pipe between the\ndemuxer and the main thread before calling finish_async().\nThen the demuxer gets a write() error and exits.\n\nThe non-error case usually just works, because we will have\nread all of the data from the other side. We do close\ndemux.out already, but we only do so _after_ calling\nfinish_async(). This is OK because there shouldn't be any\nmore data coming from the server. But technically we've only\nread to a flush packet, and a broken or malicious server\ncould be sending more cruft. In such a case, we would hit\nthe same deadlock. Closing the pipe first doesn't affect the\nnormal case, and means that for a cruft-sending server,\nwe'll notice a write() error rather than deadlocking.\n\nNote that when write() sees this error, we'll actually\ndeliver SIGPIPE to the thread, which will take down the\nwhole process (unless we're compiled with NO_PTHREADS). This\nisn't ideal, but it's an improvement over the status quo,\nwhich is deadlocking. And SIGPIPE handling in async threads\nis a bigger problem that we can deal with separately.\n\nA simple reproduction for the error case is below. It's\ntechnically racy (we could exit the main process and take\ndown the async thread with us before it even reads the\nstatus), though in practice it seems to fail pretty\nconsistently.\n\n    git init repo &&\n    cd repo &&\n\n    # make some commits; we need two so we can simulate corruption\n    # in the history later.\n    git commit --allow-empty -m one &&\n    one=$(git rev-parse HEAD) &&\n    git commit --allow-empty -m two &&\n    two=$(git rev-parse HEAD) &&\n\n    # now make a ton of refs; our goal here is to overflow the pipe buffer\n    # when reporting the ref status, which will cause the demuxer to block\n    # on write()\n    for i in $(seq 20000); do\n    \techo \"create refs/heads/this-is-a-really-long-branch-name-$i $two\"\n    done |\n    git update-ref --stdin &&\n\n    # now make a corruption in the history such that pack-objects will fail\n    rm -vf .git/objects/$(echo $one | sed 's}..}&/}') &&\n\n    # and then push the result\n    git init --bare dst.git &&\n    git push --mirror dst.git\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nEven though the SIGPIPE isn't great, it's certainly better\nthan a deadlock.  So if we had to take just this one for\n\"maint\" (e.g., because the SIGPIPE stuff causes problems on\nWindows), I think it's still worth doing (and is why I stuck\nthis patch at the front of the series).\n\nOne alternative would be to add async_cancel() which would\nrun pthread_cancel() for the threaded case, and kill() for\nthe non-threaded. That helps the error case, but makes the\nnon-error case a bit weird (if the thread _isn't_ blocking\non write to us, we want to get the real status code, rather\nthan canceling it. But we don't have any way of knowing\nwhich of _cancel() or finish() to call).\n\n send-pack.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/send-pack.c b/send-pack.c\nindex 047bd18..fc27db6 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -531,8 +531,10 @@ int send_pack(struct send_pack_args *args,\n \t\t\t\tclose(out);\n \t\t\tif (git_connection_is_socket(conn))\n \t\t\t\tshutdown(fd[0], SHUT_WR);\n-\t\t\tif (use_sideband)\n+\t\t\tif (use_sideband) {\n+\t\t\t\tclose(demux.out);\n \t\t\t\tfinish_async(&demux);\n+\t\t\t}\n \t\t\tfd[1] = -1;\n \t\t\treturn -1;\n \t\t}\n@@ -551,11 +553,11 @@ int send_pack(struct send_pack_args *args,\n \t\tpacket_flush(out);\n \n \tif (use_sideband && cmds_sent) {\n+\t\tclose(demux.out);\n \t\tif (finish_async(&demux)) {\n \t\t\terror(\"error in sideband demultiplexer\");\n \t\t\tret = -1;\n \t\t}\n-\t\tclose(demux.out);\n \t}\n \n \tif (ret < 0)\n-- \n2.8.1.512.g4e0a533\n"},{"id":"283866","messageId":"20160419224941.GB18255@sigill.intra.peff.net","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"[PATCH 2/5] run-command: teach async threads to ignore SIGPIPE","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:49:41Z","receivedAt":"2016-04-19T22:49:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"Async processes can be implemented as separate forked\nprocesses, or as threads (depending on the NO_PTHREADS\nsetting). In the latter case, if an async thread gets\nSIGPIPE, it takes down the whole process. This is obviously\nbad if the main process was not otherwise going to die, but\neven if we were going to die, it means the main process does\nnot have a chance to report a useful error message.\n\nThere's also the small matter that forked async processes\nwill not take the main process down on a signal, meaning git\nwill behave differently depending on the NO_PTHREADS\nsetting.\n\nThis patch fixes it by adding a new flag to \"struct async\"\nto block SIGPIPE just in the async thread. In theory, this\nshould always be on (which makes async threads behave more\nlike async processes), but we would first want to make sure\nthat each async process we spawn is careful about checking\nreturn codes from write() and would not spew endlessly into\na dead pipe. So let's start with it as optional, and we can\nenable it for specific sites in future patches.\n\nThe natural name for this option would be \"ignore_sigpipe\",\nsince that's what it does for the threaded case. But since\nthat name might imply that we are ignoring it in all cases\n(including the separate-process one), let's call it\n\"isolate_sigpipe\". What we are really asking for is\nisolation. I.e., not to have our main process taken down by\nsignals spawned by the async process. How that is\nimplemented is up to the run-command code.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nThis is our first use of pthread_sigmask, and I think Windows will have\nto come up with something for this in compat/. I don't know how SIGPIPE\nworks there at all, so it's possible that we can just turn this into a\nnoop. Worst case it could probably block SIGPIPE for the whole process.\n\nNote also that by blocking, we may end up with a pending SIGPIPE signal\n(so if were ever to unblock, it would get delivered). We can unqueue it\nwith sigwaitinfo(), but I _think_ it shouldn't matter. We never unblock,\nbut just kill the thread, and the pending signal should be killed with\nit.\n\nAt least that's my understanding. This is the first time I've worked\nwith signals and threads.\n\n run-command.c | 10 ++++++++++\n run-command.h |  1 +\n 2 files changed, 11 insertions(+)\n\ndiff --git a/run-command.c b/run-command.c\nindex 8c7115a..e4593cd 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -590,6 +590,16 @@ static void *run_thread(void *data)\n \tstruct async *async = data;\n \tintptr_t ret;\n \n+\tif (async->isolate_sigpipe) {\n+\t\tsigset_t mask;\n+\t\tsigemptyset(&mask);\n+\t\tsigaddset(&mask, SIGPIPE);\n+\t\tif (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {\n+\t\t\tret = error(\"unable to block SIGPIPE in async thread\");\n+\t\t\treturn (void *)ret;\n+\t\t}\n+\t}\n+\n \tpthread_setspecific(async_key, async);\n \tret = async->proc(async->proc_in, async->proc_out, async->data);\n \treturn (void *)ret;\ndiff --git a/run-command.h b/run-command.h\nindex de1727e..11f76b0 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -116,6 +116,7 @@ struct async {\n \tint proc_in;\n \tint proc_out;\n #endif\n+\tint isolate_sigpipe;\n };\n \n int start_async(struct async *async);\n-- \n2.8.1.512.g4e0a533\n"},{"id":"283867","messageId":"20160419225016.GC18255@sigill.intra.peff.net","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"[PATCH 3/5] send-pack: isolate sigpipe in demuxer thread","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:50:17Z","receivedAt":"2016-04-19T22:50:17Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"If we get an error from pack-objects, we may exit\nsend_pack() early, before reading the server's status\nresponse. In such a case, we may racily see SIGPIPE from our\nasync demuxer (which is trying to write that status back to\nus), and we'd prefer to continue pushing the error up the\ncall stack, rather than taking down the whole process with\nsignal death.\n\nThis is safe to do because our demuxer just calls\nrecv_sideband, whose data writes are all done with\nwrite_or_die(), which will notice SIGPIPE.\n\nWe do also write sideband 2 to stderr, and we would no\nlonger die on SIGPIPE there (if it were piped in the first\nplace, and if the piped program went away). But that's\nprobably a good thing, as it likewise should not abort the\npush process at all (neither immediately by signal, nor\neventually by reporting failure back to the main thread).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n send-pack.c | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/send-pack.c b/send-pack.c\nindex fc27db6..37ee04e 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -518,6 +518,7 @@ int send_pack(struct send_pack_args *args,\n \t\tdemux.proc = sideband_demux;\n \t\tdemux.data = fd;\n \t\tdemux.out = -1;\n+\t\tdemux.isolate_sigpipe = 1;\n \t\tif (start_async(&demux))\n \t\t\tdie(\"send-pack: unable to fork off sideband demultiplexer\");\n \t\tin = demux.out;\n-- \n2.8.1.512.g4e0a533\n"},{"id":"283868","messageId":"20160419225029.GD18255@sigill.intra.peff.net","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"[PATCH 4/5] fetch-pack: isolate sigpipe in demuxer thread","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:50:29Z","receivedAt":"2016-04-19T22:50:29Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"In commit 9ff18fa (fetch-pack: ignore SIGPIPE in sideband\ndemuxer, 2016-02-24), we started using sigchain_push() to\nignore SIGPIPE in the async demuxer thread. However, this is\nrather clumsy, as it ignores SIGPIPE for the entire process,\nincluding the main thread. At the time we didn't have any\nper-thread signal support, but we now we do. Let's use it.\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n fetch-pack.c | 4 +---\n 1 file changed, 1 insertion(+), 3 deletions(-)\n\ndiff --git a/fetch-pack.c b/fetch-pack.c\nindex f96f6df..b501d5c 100644\n--- a/fetch-pack.c\n+++ b/fetch-pack.c\n@@ -15,7 +15,6 @@\n #include \"version.h\"\n #include \"prio-queue.h\"\n #include \"sha1-array.h\"\n-#include \"sigchain.h\"\n \n static int transfer_unpack_limit = -1;\n static int fetch_unpack_limit = -1;\n@@ -674,10 +673,8 @@ static int sideband_demux(int in, int out, void *data)\n \tint *xd = data;\n \tint ret;\n \n-\tsigchain_push(SIGPIPE, SIG_IGN);\n \tret = recv_sideband(\"fetch-pack\", xd[0], out);\n \tclose(out);\n-\tsigchain_pop(SIGPIPE);\n \treturn ret;\n }\n \n@@ -701,6 +698,7 @@ static int get_pack(struct fetch_pack_args *args,\n \t\tdemux.proc = sideband_demux;\n \t\tdemux.data = xd;\n \t\tdemux.out = -1;\n+\t\tdemux.isolate_sigpipe = 1;\n \t\tif (start_async(&demux))\n \t\t\tdie(\"fetch-pack: unable to fork off sideband\"\n \t\t\t    \" demultiplexer\");\n-- \n2.8.1.512.g4e0a533\n"},{"id":"283869","messageId":"20160419225125.GE18255@sigill.intra.peff.net","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"[PATCH 5/5] t5504: drop sigpipe=ok from push tests","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-19T22:51:25Z","receivedAt":"2016-04-19T22:51:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"These were added by 8bf4bec (add \"ok=sigpipe\" to\ntest_must_fail and use it to fix flaky tests, 2015-11-27)\nbecause we would racily die via SIGPIPE when the pack was\nrejected by the other side.\n\nBut since we have recently de-flaked send-pack, we should be\nable to tighten up these tests (including re-adding the\nexpected output checks).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\nWould be nice to reference HEAD^2 by name here, but of\ncourse I don't know its final commit sha1 yet.\n\n t/t5504-fetch-receive-strict.sh | 10 ++++------\n 1 file changed, 4 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh\nindex a3e12d2..44f3d5f 100755\n--- a/t/t5504-fetch-receive-strict.sh\n+++ b/t/t5504-fetch-receive-strict.sh\n@@ -100,11 +100,8 @@ test_expect_success 'push with receive.fsckobjects' '\n \t\tgit config receive.fsckobjects true &&\n \t\tgit config transfer.fsckobjects false\n \t) &&\n-\ttest_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act &&\n-\t{\n-\t\ttest_cmp exp act ||\n-\t\t! test -s act\n-\t}\n+\ttest_must_fail git push --porcelain dst master:refs/heads/test >act &&\n+\ttest_cmp exp act\n '\n \n test_expect_success 'push with transfer.fsckobjects' '\n@@ -114,7 +111,8 @@ test_expect_success 'push with transfer.fsckobjects' '\n \t\tcd dst &&\n \t\tgit config transfer.fsckobjects true\n \t) &&\n-\ttest_must_fail ok=sigpipe git push --porcelain dst master:refs/heads/test >act\n+\ttest_must_fail git push --porcelain dst master:refs/heads/test >act &&\n+\ttest_cmp exp act\n '\n \n cat >bogus-commit <<\\EOF\n-- \n2.8.1.512.g4e0a533\n"},{"id":"284005","messageId":"xmqqwpnst1yb.fsf@gitster.mtv.corp.google.com","threadId":"42079","inReplyTo":"20160419223945.GA18055@sigill.intra.peff.net","subject":"Re: [PATCH 0/5] fix deadlock in git-push","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-20T21:17:16Z","receivedAt":"2016-04-20T21:17:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> The first patch below fixes the deadlock. Unfortunately, it turns it\n> into a likely SIGPIPE death. Which is an improvement, but not ideal.\n>\n> Patches 2 and 3 address that by fixing the way we handle SIGPIPE in\n> async threads.\n>\n> Patches 4 and 5 are cleanups to earlier topics that are enabled by the\n> new SIGPIPE handling.\n>\n>   [1/5]: send-pack: close demux pipe before finishing async process\n>   [2/5]: run-command: teach async threads to ignore SIGPIPE\n>   [3/5]: send-pack: isolate sigpipe in demuxer thread\n>   [4/5]: fetch-pack: isolate sigpipe in demuxer thread\n>   [5/5]: t5504: drop sigpipe=ok from push tests\n\nThanks for a very well explained series.\n\nWe do not call finish_async (rather, we do not use async) from that\nmany places, and from a cursory look this codepath is the only case\nwhere we may encounter this kind of deadlock (the ones in\nreceive-pack is about relaying the error messages back to the other\nend over sideband multiplexing)?\n"},{"id":"284009","messageId":"20160420215117.GA18297@sigill.intra.peff.net","threadId":"42079","inReplyTo":"xmqqwpnst1yb.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH 0/5] fix deadlock in git-push","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-20T21:51:17Z","receivedAt":"2016-04-20T21:51:17Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Apr 20, 2016 at 02:17:16PM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > The first patch below fixes the deadlock. Unfortunately, it turns it\n> > into a likely SIGPIPE death. Which is an improvement, but not ideal.\n> >\n> > Patches 2 and 3 address that by fixing the way we handle SIGPIPE in\n> > async threads.\n> >\n> > Patches 4 and 5 are cleanups to earlier topics that are enabled by the\n> > new SIGPIPE handling.\n> >\n> >   [1/5]: send-pack: close demux pipe before finishing async process\n> >   [2/5]: run-command: teach async threads to ignore SIGPIPE\n> >   [3/5]: send-pack: isolate sigpipe in demuxer thread\n> >   [4/5]: fetch-pack: isolate sigpipe in demuxer thread\n> >   [5/5]: t5504: drop sigpipe=ok from push tests\n> \n> Thanks for a very well explained series.\n> \n> We do not call finish_async (rather, we do not use async) from that\n> many places, and from a cursory look this codepath is the only case\n> where we may encounter this kind of deadlock (the ones in\n> receive-pack is about relaying the error messages back to the other\n> end over sideband multiplexing)?\n\nYeah, I checked the other demuxer in fetch-pack, but it does not have\nany early returns like this (it just dies :) ).\n\nIt does not do an explicit close on demux.out, but I think it is\neffectively closed when we hand it off to index-pack/unpack-objects via\ncmd.in.\n\nArguably finish_async() should \"close(demux.out)\" itself, but that felt\nlike an ownership violation. Yes, that's how \"struct async\" passes out\nthe descriptor, but the caller is then expected to handle it, and\ncorrect callers will typically have closed it themselves, handed it off\nto a sub-process, etc. Closing it in finish_async() runs the risk that\nwe just call close() on a descriptor number that is either unattached,\nor attached to some random other thing.\n\n-Peff\n"},{"id":"284016","messageId":"571861EE.1080202@kdbg.org","threadId":"42079","inReplyTo":"20160419224941.GB18255@sigill.intra.peff.net","subject":"Re: [PATCH 2/5] run-command: teach async threads to ignore SIGPIPE","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2016-04-21T05:15:26Z","receivedAt":"2016-04-21T05:15:26Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 20.04.2016 um 00:49 schrieb Jeff King:\n> This is our first use of pthread_sigmask, and I think Windows will have\n> to come up with something for this in compat/. I don't know how SIGPIPE\n> works there at all, so it's possible that we can just turn this into a\n> noop. Worst case it could probably block SIGPIPE for the whole process.\n\nThere is no SIGPIPE on Windows. write() always returns EPIPE as if \nSIGPIPE was ignored.\n\nWe'll have to make pthread_sigmask() a no-op.\n\n-- Hannes\n"},{"id":"284017","messageId":"20160421051856.GA23270@sigill.intra.peff.net","threadId":"42079","inReplyTo":"571861EE.1080202@kdbg.org","subject":"Re: [PATCH 2/5] run-command: teach async threads to ignore SIGPIPE","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-21T05:18:57Z","receivedAt":"2016-04-21T05:18:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 21, 2016 at 07:15:26AM +0200, Johannes Sixt wrote:\n\n> Am 20.04.2016 um 00:49 schrieb Jeff King:\n> >This is our first use of pthread_sigmask, and I think Windows will have\n> >to come up with something for this in compat/. I don't know how SIGPIPE\n> >works there at all, so it's possible that we can just turn this into a\n> >noop. Worst case it could probably block SIGPIPE for the whole process.\n> \n> There is no SIGPIPE on Windows. write() always returns EPIPE as if SIGPIPE\n> was ignored.\n> \n> We'll have to make pthread_sigmask() a no-op.\n\nGreat, thanks for clarifying. We can also #ifdef out the whole block\nthere if it's easier, but it looks like you already have noop\nimplementations for sigset, et al. So adding a noop pthread_sigmask()\nshould be enough.\n\n-Peff\n"}]}