Skip to content

Commit ef1cf01

Browse files
Eric Wonggitster
authored andcommitted
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: 1079c4b ("xread: poll on non blocking fds") Signed-off-by: Eric Wong <[email protected]> Reviewed-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent c22f620 commit ef1cf01

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

wrapper.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,26 @@ ssize_t xwrite(int fd, const void *buf, size_t len)
271271
len = MAX_IO_SIZE;
272272
while (1) {
273273
nr = write(fd, buf, len);
274-
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
275-
continue;
274+
if (nr < 0) {
275+
if (errno == EINTR)
276+
continue;
277+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
278+
struct pollfd pfd;
279+
pfd.events = POLLOUT;
280+
pfd.fd = fd;
281+
/*
282+
* it is OK if this poll() failed; we
283+
* want to leave this infinite loop
284+
* only when write() returns with
285+
* success, or an expected failure,
286+
* which would be checked by the next
287+
* call to write(2).
288+
*/
289+
poll(&pfd, 1, -1);
290+
continue;
291+
}
292+
}
293+
276294
return nr;
277295
}
278296
}

0 commit comments

Comments
 (0)