Just looking at this select! example; what are the exact conditions that are required to achieve cancel safety (or not)?
My assumption is that iff read_msg()'s Future does not store any of the data from its underlying transport in itself, then it's cancel safe. (I.e. it's safe if it will only extract data from its underlying transport when a complete message can be returned immediately using Poll::Ready).
Is cancel non-safety an effect of a partial buffer being extracted and stored in the returned Future (by read_msg()) but then wait_for_kill sneaks in and yields Pending::Ready?
Is there more to it, or is that the basic gist of it?
The underlying issue with cancellation safety is that all futures in the select other than the future that yields Poll::Ready will be dropped. If those futures own some form of state, then your future is not cancellation safe, since that owned state will be dropped when another future returns Poll::Ready.
The easy way to avoid this is for the futures in the select! to not own state, but to borrow it from elsewhere; for example, if buffered_stream owns all the state, and the future returned by read_msg() mutates buffered_stream instead of storing its own state, you're cancellation-safe. This happens with recv on Tokio channels, since all the state is in the channel, and not in the future returned by recv().
Good point. The thing I'm actually doing is handling a read, a kill and receiving a translated SIGHUP-to-"reload configuration" message, but I wanted something more compact as an illustration. Going with the "kill" rather than the "reload" in this context was clearly not my brightest move.