Fixed intermittent CPP sync server shutdown leak.

Specifically: if a request handling thread is in flight but scheduled
out when shutdown is called on the server, but it has already passed
the shutdown check, then when it resumes it will add a grpc_call to
the completion queue that is leaked. We fix this by explicitly freeing
such calls after all worker threads have shutdown.

To manifest the leak, run the end2end::ClientCancelsRequestStream
test repeatedly on the unpatched server implementation. About 0.5% of
the time, the leak will manifest.
pull/17151/head
Arjun Roy 6 years ago
parent 38c6b2c72a
commit 843c8d9e75
  1. 23
      src/cpp/server/server_cc.cc

@ -199,9 +199,20 @@ class Server::SyncRequest final : public internal::CompletionQueueTag {
}
}
void PostShutdownCleanup() {
if (call_) {
grpc_call_unref(call_);
}
if (cq_) {
grpc_completion_queue_destroy(cq_);
cq_ = nullptr;
}
}
bool FinalizeResult(void** tag, bool* status) override {
if (!*status) {
grpc_completion_queue_destroy(cq_);
cq_ = nullptr;
}
if (call_details_) {
deadline_ = call_details_->deadline;
@ -586,7 +597,17 @@ class Server::SyncRequestThreadManager : public ThreadManager {
void* tag;
bool ok;
while (server_cq_->Next(&tag, &ok)) {
// Do nothing
if (ok) {
// If a request was pulled off the queue, it means that the thread
// handling the request added it to the completion queue after shutdown
// was called - because the thread had already started and checked the
// shutdown flag before shutdown was called. In this case, we simply
// clean it up here, *after* calling wait on all the worker threads, at
// which point we are certain no in-flight requests will add more to the
// queue. This fixes an intermittent memory leak on shutdown.
SyncRequest* sync_req = static_cast<SyncRequest*>(tag);
sync_req->PostShutdownCleanup();
}
}
}

Loading…
Cancel
Save