Change PipeStream's sync I/O cancellation support to avoid blocking CancellationTokenSource.Cancel (#72612)
* Change PipeStream's sync I/O cancellation support to avoid blocking CancellationTokenSource.Cancel
In a degenerate case, where cancellation is requested between the cancellation being registered and the I/O being performed, and where the thread performing the I/O is delayed significantly, the thread calling CTS.Cancel to cancel the operation could be blocked waiting for the callback cancellation loop which is in turn waiting for the I/O to be performed.
This changes the implementation to not block Cancel by instead queueing the cancellation handling.
It also factors the whole implementation of the async-over-sync support into a helper class, setting us up to reuse it elsewhere as needed (and cleaning up the PipeStream code to avoid duplication).
* Address PR feedback
* Address PR feedback (and a few other tweaks)