diff options
| author | Junio C Hamano <gitster@pobox.com> | 2022-08-25 14:42:31 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2022-08-25 14:42:32 -0700 |
| commit | a103ad6f3d58cf3d297a6b102876e2bbf09c98d7 (patch) | |
| tree | 763c63d41c7c3d9fadf0ebbe76e9fc90f81743a8 /run-command.c | |
| parent | 098b7bfaa6c415f2b23885b82d6b5a31a8cdb7d2 (diff) | |
| parent | 716c1f649e372a0784b9826cd3839e7b373e2ea9 (diff) | |
| download | git-a103ad6f3d58cf3d297a6b102876e2bbf09c98d7.tar.xz | |
Merge branch 'jk/pipe-command-nonblock'
Fix deadlocks between main Git process and subprocess spawned via
the pipe_command() API, that can kill "git add -p" that was
reimplemented in C recently.
* jk/pipe-command-nonblock:
pipe_command(): mark stdin descriptor as non-blocking
pipe_command(): handle ENOSPC when writing to a pipe
pipe_command(): avoid xwrite() for writing to pipe
git-compat-util: make MAX_IO_SIZE define globally available
nonblock: support Windows
compat: add function to enable nonblocking pipes
Diffstat (limited to 'run-command.c')
| -rw-r--r-- | run-command.c | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/run-command.c b/run-command.c index 14f17830f5..5ec3a46dcc 100644 --- a/run-command.c +++ b/run-command.c @@ -10,6 +10,7 @@ #include "config.h" #include "packfile.h" #include "hook.h" +#include "compat/nonblock.h" void child_process_init(struct child_process *child) { @@ -1364,12 +1365,25 @@ static int pump_io_round(struct io_pump *slots, int nr, struct pollfd *pfd) continue; if (io->type == POLLOUT) { - ssize_t len = xwrite(io->fd, - io->u.out.buf, io->u.out.len); + ssize_t len; + + /* + * Don't use xwrite() here. It loops forever on EAGAIN, + * and we're in our own poll() loop here. + * + * Note that we lose xwrite()'s handling of MAX_IO_SIZE + * and EINTR, so we have to implement those ourselves. + */ + len = write(io->fd, io->u.out.buf, + io->u.out.len <= MAX_IO_SIZE ? + io->u.out.len : MAX_IO_SIZE); if (len < 0) { - io->error = errno; - close(io->fd); - io->fd = -1; + if (errno != EINTR && errno != EAGAIN && + errno != ENOSPC) { + io->error = errno; + close(io->fd); + io->fd = -1; + } } else { io->u.out.buf += len; io->u.out.len -= len; @@ -1438,6 +1452,15 @@ int pipe_command(struct child_process *cmd, return -1; if (in) { + if (enable_pipe_nonblock(cmd->in) < 0) { + error_errno("unable to make pipe non-blocking"); + close(cmd->in); + if (out) + close(cmd->out); + if (err) + close(cmd->err); + return -1; + } io[nr].fd = cmd->in; io[nr].type = POLLOUT; io[nr].u.out.buf = in; |
