[c++ grpc] Drop client callback after executing

After executing the client callback upon receiving a response, clear the
stored callback to prevent a shared_ptr cycle.

Previously, when the callback function was not cleared, if the callback
happened to store the unary_call_result that it was invoked with (like
wait_callback does), there would be a shared_ptr cycle: the callback
would have a shared_ptr to the unary_call_result, which was keeping its
parent client_unary_call_data alive. This client_unary_call_data had a
copy of the callback function, which had a shared_ptr to the
unary_call_result.

This change resets the callback to empty after is has been executed,
breaking the cycle.
This commit is contained in:
Christopher Warrington 2017-09-28 13:53:10 -07:00 коммит произвёл Chad Walters
Родитель f96af1ffe1
Коммит 554125145d
2 изменённых файлов: 13 добавлений и 7 удалений

Просмотреть файл

@ -40,7 +40,8 @@ different versioning scheme, following the Haskell community's
causing a stack overflow.
* Guard against min/max being function-style macros in more places.
* Provide compile-time access to metadata about gRPC services and methods.
* Using `bond::ext::gRPC::wait_callback` no longer causes a shared_ptr cycle
and the resulting resource leak.
### C# ###

Просмотреть файл

@ -51,14 +51,14 @@ struct client_unary_call_data
std::shared_ptr<TThreadPool> _threadPool;
/// A response reader.
std::unique_ptr<grpc::ClientAsyncResponseReader<bond::bonded<TResponse>>> _responseReader;
/// The arguments to pass back into the client callback. Also doubles as
/// The arguments to pass back into the client callback. Also doubles as
/// storage for the response, status, and context.
unary_call_result<TResponse> _callbackArgs;
/// A pointer to ourselves used to keep us alive while waiting to receive
/// the response.
std::shared_ptr<client_unary_call_data> _self;
/// The user code to invoke when a response is received.
CallbackType _cb;
/// A pointer to ourselves used to keep us alive while waiting to
/// receive the response.
std::shared_ptr<client_unary_call_data> _self;
client_unary_call_data(
std::shared_ptr<grpc::ChannelInterface> channel,
@ -71,8 +71,8 @@ struct client_unary_call_data
_threadPool(std::move(threadPool)),
_responseReader(),
_callbackArgs(context),
_self(),
_cb(cb)
_cb(cb),
_self()
{
BOOST_ASSERT(_channel);
BOOST_ASSERT(_ioManager);
@ -133,6 +133,11 @@ struct client_unary_call_data
_ioManager.reset();
_threadPool.reset();
_responseReader.reset();
_cb = {};
// In case we're the only reference keeping ourselves alive, we need
// to clear _self last so we don't attempt to access a local after
// this instance has been destroyed.
_self.reset();
}
};