Skip to content

Commit 14eab81

Browse files
peffgitster
authored andcommitted
pipe_command(): avoid xwrite() for writing to pipe
If xwrite() sees an EAGAIN response, it will loop forever until the write succeeds (or encounters a real error). This is due to ef1cf01 (xwrite: poll on non-blocking FDs, 2016-06-26), with the idea that we won't be surprised by a descriptor unexpectedly set as non-blocking. But that will make things awkward when we do want a non-blocking descriptor, and a future patch will switch pipe_command() to using one. In that case, looping on EAGAIN is bad, because the process on the other end of the pipe may be waiting on us before doing another read() on the pipe, which would mean we deadlock. In practice we're not supposed to ever see EAGAIN here, since poll() will have just told us the descriptor is ready for writing. But our Windows emulation of poll() will always return "ready" for writing to a pipe descriptor! This is due to 94f4d01 (mingw: workaround for hangs when sending STDIN, 2020-02-17). Our best bet in that case is to keep handling other descriptors, as any read() we do may allow the child command to make forward progress (i.e., its write() finishes, and then it read()s from its stdin, freeing up space in the pipe buffer). This means we might busy-loop between poll() and write() on Windows if the child command is slow to read our input, but it's much better than the alternative of deadlocking. In practice, this busy-looping should be rare: - for small inputs, we'll just write the whole thing in a single write() anyway, non-blocking or not - for larger inputs where the child reads input and then processes it before writing (e.g., gpg verifying a signature), we may make a few extra write() calls that get EAGAIN during the initial write, but once it has taken in the whole input, we'll correctly block waiting to read back the data. - for larger inputs where the child process is streaming output back (like a diff filter), we'll likewise see some extra EAGAINs, but most of them will be followed immediately by a read(), which will let the child command make forward progress. Of course it won't happen at all for now, since we don't yet use a non-blocking pipe. This is just preparation for when we do. Helped-by: René Scharfe <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ec4f39b commit 14eab81

File tree

1 file changed

+17
-5
lines changed

1 file changed

+17
-5
lines changed

run-command.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,12 +1364,24 @@ static int pump_io_round(struct io_pump *slots, int nr, struct pollfd *pfd)
13641364
continue;
13651365

13661366
if (io->type == POLLOUT) {
1367-
ssize_t len = xwrite(io->fd,
1368-
io->u.out.buf, io->u.out.len);
1367+
ssize_t len;
1368+
1369+
/*
1370+
* Don't use xwrite() here. It loops forever on EAGAIN,
1371+
* and we're in our own poll() loop here.
1372+
*
1373+
* Note that we lose xwrite()'s handling of MAX_IO_SIZE
1374+
* and EINTR, so we have to implement those ourselves.
1375+
*/
1376+
len = write(io->fd, io->u.out.buf,
1377+
io->u.out.len <= MAX_IO_SIZE ?
1378+
io->u.out.len : MAX_IO_SIZE);
13691379
if (len < 0) {
1370-
io->error = errno;
1371-
close(io->fd);
1372-
io->fd = -1;
1380+
if (errno != EINTR && errno != EAGAIN) {
1381+
io->error = errno;
1382+
close(io->fd);
1383+
io->fd = -1;
1384+
}
13731385
} else {
13741386
io->u.out.buf += len;
13751387
io->u.out.len -= len;

0 commit comments

Comments
 (0)