aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cpp/server
diff options
context:
space:
mode:
authorGravatar Arjun Roy <arjunroy@google.com>2018-11-07 17:39:07 -0800
committerGravatar Arjun Roy <arjunroy@google.com>2018-11-07 17:39:07 -0800
commit843c8d9e75acca671090df8d7f95d4eb973c88ff (patch)
tree73fe1b397b404ef5c61c19f851d0bea236857732 /src/cpp/server
parent38c6b2c72a9489de0ba350d1493b063fa8f6d424 (diff)
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.
Diffstat (limited to 'src/cpp/server')
-rw-r--r--src/cpp/server/server_cc.cc23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index c031528a8f..774c33b31a 100644
--- a/src/cpp/server/server_cc.cc
+++ b/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();
+ }
}
}