Am 05.08.2022 um 17:36 schrieb Jeff King: > On Wed, Aug 03, 2022 at 11:56:13PM +0200, René Scharfe wrote: > >> Without that line the added test hangs for me on the Git for Windows >> SDK on Windows 11. > > Hmph. Interesting that it passes in CI, but not on your local setup. > I wonder why pipes would behave differently. Or perhaps there is even > some configuration different that means we are still running the perl > add--interactive there, though I kind of doubt it (and couldn't find > anything pointing there). > > Still, if it fails in at least one spot, it's something we need to deal > with. On the plus side, once we figure out how to fix it, the > hand-grenade of "enable_nonblock() does nothing on Windows" will not be > present anymore. ;) > >> With the patch below it fails and reports basically nothing: >> [...] >> not ok 57 - handle very large filtered diff >> # >> # git reset --hard && >> # # The specific number here is not important, but it must >> # # be large enough that the output of "git diff --color" >> # # fills up the pipe buffer. 10,000 results in ~200k of >> # # colored output. >> # test_seq 10000 >test && >> # test_config interactive.diffFilter cat && >> # printf y >y && >> # force_color git add -p >output 2>&1 <y && >> # git diff-files --exit-code -- test >> # >> 1..57 >> >> The file "output" contains "error: failed to run 'cat'". This is >> add-patch.c::parse_diff() reporting that pipe_command() failed. So >> that's not it, yet. (I don't actually know what I'm doing here.) > > That implies that your call to enable_nonblock() succeeded, or > pipe_command() itself would have complained, too. Maybe instrument > it like this: > > diff --git a/run-command.c b/run-command.c > index 8ea609d4ae..27e79c928a 100644 > --- a/run-command.c > +++ b/run-command.c > @@ -1473,11 +1473,17 @@ int pipe_command(struct child_process *cmd, > } > > if (pump_io(io, nr) < 0) { > + error_errno("pumping io failed"); > finish_command(cmd); /* throw away exit code */ > return -1; > } > > - return finish_command(cmd); > + { > + int ret = finish_command(cmd); > + if (ret) > + error("child returned failure %d", ret); > + return ret; > + } > } > > enum child_state { > > Normally we stay pretty quiet there and let the caller report any > problems, but it lacks enough context to make a more specific error > report. This adds "error: pumping io failed: No space left on device" to output. Which kinda makes sense: With the pipe no longer blocking, there can be a moment when the buffer is full and writes have to be rejected. This condition should be reported with EAGAIN, though. Adding "if (len < 0 && errno == ENOSPC) continue;" after the xwrite() call in pump_io_round() lets the test pass. Perhaps the translation from Windows error code to POSIX is wrong here? > >> int enable_nonblock(int fd) >> { >> + DWORD mode; >> + HANDLE handle = winansi_get_osfhandle(fd); >> + if (!handle) >> + return -1; >> + if (!GetNamedPipeHandleState(handle, &mode, NULL, NULL, NULL, NULL, 0)) >> + return -1; >> + if (mode & PIPE_NOWAIT) >> + return 0; >> + mode |= PIPE_NOWAIT; >> + if (!SetNamedPipeHandleState(handle, &mode, NULL, NULL)) >> + return -1; >> return 0; >> } > > This looks plausibly correct to me. ;) We might want to change the name > of the compat layer to enable_pipe_nonblock(), since one assumes from > the function names this only works for pipes. Right, and the "Named" part should be explained: As [1] says: "[...] you can often pass a handle to an anonymous pipe to a function that requires a handle to a named pipe.". And perhaps that's not the right thing to do after all, as [2] says: "Note that nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve asynchronous input and output (I/O) [...]". [1] https://docs.microsoft.com/en-us/windows/win32/ipc/anonymous-pipe-operations [2] https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate > > Thanks for poking at this. > > -Peff