I have encountered two situations where a blocking call never returns (or after at least ~10 minutes I have lost patience and killed the client process).
I open a channel to an embedded device that is NOT grpc enabled and talks an proprietary TCP protocol instead.
Instead of closing the socket this devices responds to the unknown protocol by sending a single NAK (0x15) byte.
I have a running connection using grpc. Now I pull the servers network cable.
In both situations I can see the function grpc_iocp_work waiting indefinite on the Windows API call to GetQueuedCompletionStatus.
ntdll.dll!NtRemoveIoCompletion()
KernelBase.dll!GetQueuedCompletionStatus()
kernel32.dll!GetQueuedCompletionStatusStub()
TestAppD.exe!grpc_iocp_work(grpc_exec_ctx * exec_ctx=0x000000000a28e678, gpr_timespec deadline={...}) Line 68
TestAppD.exe!grpc_pollset_work(grpc_exec_ctx * exec_ctx=0x000000000a28e678, grpc_pollset * pollset=0x000000000863f7e0, grpc_pollset_worker * * worker_hdl=0x000000000a28e5d8, gpr_timespec now={...}, gpr_timespec deadline={...}) Line 133
TestAppD.exe!cq_pluck(grpc_completion_queue * cq=0x000000000863f6a0, void * tag=0x000000000a28ea50, gpr_timespec deadline={...}, void * reserved=0x0000000000000000) Line 1149
TestAppD.exe!grpc_completion_queue_pluck(grpc_completion_queue * cq=0x000000000863f6a0, void * tag=0x000000000a28ea50, gpr_timespec deadline={...}, void * reserved=0x0000000000000000) Line 1179
TestAppD.exe!grpc::CoreCodegen::grpc_completion_queue_pluck(grpc_completion_queue * cq=0x000000000863f6a0, void * tag=0x000000000a28ea50, gpr_timespec deadline={...}, void * reserved=0x0000000000000000) Line 72
TestAppD.exe!grpc::CompletionQueue::Pluck(grpc::CompletionQueueTag * tag=0x000000000a28ea50) Line 225
TestAppD.exe!grpc::BlockingUnaryCall<GrpcTestApp::TestSyncRequest,GrpcTestApp::TestSyncReply>(grpc::ChannelInterface * channel=0x000000000693b490, const grpc::RpcMethod & method={...}, grpc::ClientContext * context=0x000000000a28ef80, const GrpcTestApp::TestSyncRequest & request={...}, GrpcTestApp::TestSyncReply * result=0x000000000a28edb8) Line 59
TestAppD.exe!GrpcTestApp::CommTest::Stub::TestSync(grpc::ClientContext * context=0x000000000a28ef80, const GrpcTestApp::TestSyncRequest & request={...}, GrpcTestApp::TestSyncReply * response=0x000000000a28edb8) Line 34
If I kill the server's process any client call returns with Status == UNAVAILABLE immediately. So this situation is handled correctly.