diff --git a/stub/src/main/java/io/grpc/stub/BlockingClientCall.java b/stub/src/main/java/io/grpc/stub/BlockingClientCall.java index 27bd42e53bb..e0390a7475b 100644 --- a/stub/src/main/java/io/grpc/stub/BlockingClientCall.java +++ b/stub/src/main/java/io/grpc/stub/BlockingClientCall.java @@ -249,6 +249,13 @@ void sendSingleRequest(ReqT request) { public void cancel(String message, Throwable cause) { writeClosed = true; call.cancel(message, cause); + // 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 in order to ensure all call + // tasks run. + executor.becomeDirect(); } /** diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index ff2804a0a1f..6432523a9bb 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -871,6 +871,7 @@ static final class ThreadSafeThreadlessExecutor extends ConcurrentLinkedQueue