Merge branch 'jk/pipe-command-nonblock' into maint

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
This commit is contained in:
Junio C Hamano
2022-09-13 12:21:08 -07:00
7 changed files with 123 additions and 27 deletions

50
compat/nonblock.c Normal file
View File

@@ -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

9
compat/nonblock.h Normal file
View File

@@ -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