aboutsummaryrefslogtreecommitdiff
path: root/wrapper.c
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2016-06-26 23:21:12 +0000
committerJunio C Hamano <gitster@pobox.com>2016-06-27 08:34:15 -0700
commitef1cf0167a362cd504afdcc0eef4c3200ea6dfbb (patch)
tree16d11b77fbdbcd297617073c3cedfe2070ddef3d /wrapper.c
parentc22f6202052ca84c68df4fbb16e42c826d429558 (diff)
downloadgit-ef1cf0167a362cd504afdcc0eef4c3200ea6dfbb.tar.gz
git-ef1cf0167a362cd504afdcc0eef4c3200ea6dfbb.tar.xz
xwrite: poll on non-blocking FDs
write(2) can hit the same EAGAIN/EWOULDBLOCK errors as read(2), so busy-looping on a non-blocking FD is a waste of resources. Currently, I do not know of a way for this happen: * the NonBlocking directive in systemd does not apply to stdin, stdout, or stderr. * xinetd provides no way to set the non-blocking flag at all But theoretically, it's possible a careless C10K HTTP server could use pipe2(..., O_NONBLOCK) to setup a pipe for git-http-backend with only the intent to use non-blocking reads; but accidentally leave non-blocking set on the write end passed as stdout to git-upload-pack. Followup-to: 1079c4be0b720 ("xread: poll on non blocking fds") Signed-off-by: Eric Wong <e@80x24.org> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'wrapper.c')
-rw-r--r--wrapper.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/wrapper.c b/wrapper.c
index 9b20eb935..f7ea6c43b 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -271,8 +271,26 @@ ssize_t xwrite(int fd, const void *buf, size_t len)
len = MAX_IO_SIZE;
while (1) {
nr = write(fd, buf, len);
- if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
- continue;
+ if (nr < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ struct pollfd pfd;
+ pfd.events = POLLOUT;
+ pfd.fd = fd;
+ /*
+ * it is OK if this poll() failed; we
+ * want to leave this infinite loop
+ * only when write() returns with
+ * success, or an expected failure,
+ * which would be checked by the next
+ * call to write(2).
+ */
+ poll(&pfd, 1, -1);
+ continue;
+ }
+ }
+
return nr;
}
}