I see that `cs.blockUntilEnded` does not throw an exception if the task fails, so that's good.
However, I think `blockUntilEnded` has a bug: it catches Throwable without doing `Exceptions.propagateIfFatal`. e.g. if the thread calling `join()` is interrupted then the interrupt will be swallowed and the thread won't return properly, which is bad.