In this case, b/c we are explicitly spawning threads, we are talking about synchronous programming. You can spin-up an event loop inside the thread, of course, and then you’ll need to somehow plug the is_canceled call into the select/epoll that drives the loop.
As soon as the read call returns (either timeout or gets some data),
Unfortunately, that might not always be possible, the “file” is some kind of IPC mechanism, where the blocking is indefinite. For example, in Cargo we need to play some tricks with signals to wake up a read which blocks on a pipe: https://github.com/alexcrichton/jobserver-rs/blob/cddd571ab014a66c52728c9599ded17d5f838927/src/lib.rs#L280-L287