MonitorFdHup: Make it work on macOS again

It appears that on current macOS versions, our use of poll() to detect
client disconnects no longer works. As a workaround, poll() for
POLLRDNORM, since this *will* wake up when the client has
disconnected. The downside is that it also wakes up when input is
available. So just sleep for a bit in that case.  This means that on
macOS, a client disconnect may take up to a second to be detected,
but that's better than not being detected at all.

Fixes #7584.
This commit is contained in:
Eelco Dolstra 2023-01-11 10:48:40 -08:00
parent 6dd8b3b412
commit 9fc8d00d74

View file

@ -22,27 +22,38 @@ public:
{ {
thread = std::thread([fd]() { thread = std::thread([fd]() {
while (true) { while (true) {
/* Wait indefinitely until a POLLHUP occurs. */ /* Wait indefinitely until a POLLHUP occurs. */
struct pollfd fds[1]; struct pollfd fds[1];
fds[0].fd = fd; fds[0].fd = fd;
/* This shouldn't be necessary, but macOS doesn't seem to /* Polling for no specific events (i.e. just waiting
like a zeroed out events field. for an error/hangup) doesn't work on macOS
See rdar://37537852. anymore. So wait for read events and ignore
*/ them. */
fds[0].events = POLLHUP; fds[0].events =
auto count = poll(fds, 1, -1); #ifdef __APPLE__
if (count == -1) abort(); // can't happen POLLRDNORM
/* This shouldn't happen, but can on macOS due to a bug. #else
See rdar://37550628. 0
#endif
;
auto count = poll(fds, 1, -1);
if (count == -1) abort(); // can't happen
/* This shouldn't happen, but can on macOS due to a bug.
See rdar://37550628.
This may eventually need a delay or further This may eventually need a delay or further
coordination with the main thread if spinning proves coordination with the main thread if spinning proves
too harmful. too harmful.
*/ */
if (count == 0) continue; if (count == 0) continue;
assert(fds[0].revents & POLLHUP); if (fds[0].revents & POLLHUP) {
triggerInterrupt(); triggerInterrupt();
break; break;
}
/* This will only happen on macOS. We sleep a bit to
avoid waking up too often if the client is sending
input. */
sleep(1);
} }
}); });
}; };