diff options
author | Junio C Hamano <gitster@pobox.com> | 2022-08-25 23:42:31 +0200 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2022-08-25 23:42:32 +0200 |
commit | a103ad6f3d58cf3d297a6b102876e2bbf09c98d7 (patch) | |
tree | 763c63d41c7c3d9fadf0ebbe76e9fc90f81743a8 /compat | |
parent | Merge branch 'js/fetch-negotiation-trace' (diff) | |
parent | pipe_command(): mark stdin descriptor as non-blocking (diff) | |
download | git-a103ad6f3d58cf3d297a6b102876e2bbf09c98d7.tar.xz git-a103ad6f3d58cf3d297a6b102876e2bbf09c98d7.zip |
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 'compat')
-rw-r--r-- | compat/nonblock.c | 50 | ||||
-rw-r--r-- | compat/nonblock.h | 9 |
2 files changed, 59 insertions, 0 deletions
diff --git a/compat/nonblock.c b/compat/nonblock.c new file mode 100644 index 0000000000..9694ebdb1d --- /dev/null +++ b/compat/nonblock.c @@ -0,0 +1,50 @@ +#include "git-compat-util.h" +#include "nonblock.h" + +#ifdef O_NONBLOCK + +int enable_pipe_nonblock(int fd) +{ + int flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -1; + flags |= O_NONBLOCK; + return fcntl(fd, F_SETFL, flags); +} + +#elif defined(GIT_WINDOWS_NATIVE) + +#include "win32.h" + +int enable_pipe_nonblock(int fd) +{ + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD mode; + DWORD type = GetFileType(h); + if (type == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) { + errno = EBADF; + return -1; + } + if (type != FILE_TYPE_PIPE) + BUG("unsupported file type: %lu", type); + if (!GetNamedPipeHandleState(h, &mode, NULL, NULL, NULL, NULL, 0)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + mode |= PIPE_NOWAIT; + if (!SetNamedPipeHandleState(h, &mode, NULL, NULL)) { + errno = err_win_to_posix(GetLastError()); + return -1; + } + return 0; +} + +#else + +int enable_pipe_nonblock(int fd) +{ + errno = ENOSYS; + return -1; +} + +#endif diff --git a/compat/nonblock.h b/compat/nonblock.h new file mode 100644 index 0000000000..af1a331301 --- /dev/null +++ b/compat/nonblock.h @@ -0,0 +1,9 @@ +#ifndef COMPAT_NONBLOCK_H +#define COMPAT_NONBLOCK_H + +/* + * Enable non-blocking I/O for the pipe specified by the passed-in descriptor. + */ +int enable_pipe_nonblock(int fd); + +#endif |