From 10f743389ca9a92720fb9c3d15f647888d82c297 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 17 Aug 2022 02:04:55 -0400 Subject: compat: add function to enable nonblocking pipes We'd like to be able to make some of our pipes nonblocking so that poll() can be used effectively, but O_NONBLOCK isn't portable. Let's introduce a compat wrapper so this can be abstracted for each platform. The interface is as narrow as possible to let platforms do what's natural there (rather than having to implement fcntl() and a fake O_NONBLOCK for example, or having to handle other types of descriptors). The next commit will add Windows support, at which point we should be covering all platforms in practice. But if we do find some other platform without O_NONBLOCK, we'll return ENOSYS. Arguably we could just trigger a build-time #error in this case, which would catch the problem earlier. But since we're not planning to use this compat wrapper in many code paths, a seldom-seen runtime error may be friendlier for such a platform than blocking compilation completely. Our test suite would still notice it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- compat/nonblock.c | 23 +++++++++++++++++++++++ compat/nonblock.h | 9 +++++++++ 2 files changed, 32 insertions(+) create mode 100644 compat/nonblock.c create mode 100644 compat/nonblock.h (limited to 'compat') diff --git a/compat/nonblock.c b/compat/nonblock.c new file mode 100644 index 0000000000..b08105a21d --- /dev/null +++ b/compat/nonblock.c @@ -0,0 +1,23 @@ +#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); +} + +#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 -- cgit v1.2.3 From 24b56ae4aecc937a246efb94d283f54a7f59c7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Wed, 17 Aug 2022 02:05:25 -0400 Subject: nonblock: support Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement enable_pipe_nonblock() using the Windows API. This works only for pipes, but that is sufficient for this limited interface. Despite the API calls used, it handles both "named" and anonymous pipes from our pipe() emulation. Signed-off-by: René Scharfe Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- compat/nonblock.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'compat') diff --git a/compat/nonblock.c b/compat/nonblock.c index b08105a21d..9694ebdb1d 100644 --- a/compat/nonblock.c +++ b/compat/nonblock.c @@ -12,6 +12,33 @@ int enable_pipe_nonblock(int fd) 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) -- cgit v1.2.3