stub: ensure BlockingClientCall tasks run after cancellation
After canceling a BlockingClientCall, the caller may not interact with it further. That means the call executor, a ThreadSafeThreadlessExecutor, will not execute any more tasks. There may still be tasks submitted to the call executor, though, until the underlying call completes. Some of these tasks (e.g., server messages available) may leak native resources unless executed. So, we convert the executor to a "direct" executor during cancellation in order to ensure all call tasks run.
Fixes https://github.com/grpc/grpc-java/issues/12355.
The trouble is I don't think .cancel should be blocking.
Another option might be to dump post-cancellation tasks on whatever executor would have been used for the call if we didn't force ThreadsafeThreadlessExecutor in.
I expect we really want to drain the executor until the Listener.onClose() is delivered.
So you're proposal would be to make BlockingClientCall.cancel look something like this?
public void cancel(String message, Throwable cause) {
writeClosed = true;
call.cancel(message, cause);
boolean interrupted = Thread.interrupted();
while (true) {
try {
executor.waitAndDrain(x -> x.closeState.get() != null, this);
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}