> The fix was pretty straightforward: instead of using QueueUserAPC(), we now create a loopback socket to which we send a byte any time we need to interrupt select().
Ha, I have always been using this trick to break from a blocking select() call. I feel less evil now.
On Linux and macOS you could also use a pipe instead since select() doesn't only work with sockets.
On Windows you can alternatively use WSAEventSelect (https://docs.microsoft.com/en-us/windows/win32/api/winsock2/...) on all sockets and have another Event just for signalling, but the downside is that it forces your sockets to be non-blocking.