You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2017/01/05 16:32:36 UTC
mesos git commit: Fixed memory leak in implementation of
Future::after().
Repository: mesos
Updated Branches:
refs/heads/master b2d36ed69 -> be127e6ec
Fixed memory leak in implementation of Future<T>::after().
Removes a reference counted pointer that futures kept to themselves
when using the method `Future<T>::after()`.
Review: https://reviews.apache.org/r/53299/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/be127e6e
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/be127e6e
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/be127e6e
Branch: refs/heads/master
Commit: be127e6eca1312bf8c2b039646f6909fa42cd342
Parents: b2d36ed
Author: Alexander Rojas <al...@mesosphere.io>
Authored: Thu Jan 5 10:43:02 2017 -0500
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Thu Jan 5 11:32:23 2017 -0500
----------------------------------------------------------------------
3rdparty/libprocess/include/process/future.hpp | 23 ++++++++++++------
3rdparty/libprocess/src/tests/future_tests.cpp | 26 +++++++++++++++++++++
2 files changed, 42 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/be127e6e/3rdparty/libprocess/include/process/future.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/future.hpp b/3rdparty/libprocess/include/process/future.hpp
index 26bf585..71171c6 100644
--- a/3rdparty/libprocess/include/process/future.hpp
+++ b/3rdparty/libprocess/include/process/future.hpp
@@ -1334,7 +1334,7 @@ void expired(
const lambda::function<Future<T>(const Future<T>&)>& f,
const std::shared_ptr<Latch>& latch,
const std::shared_ptr<Promise<T>>& promise,
- const Future<T>& future)
+ const WeakFuture<T>& weak_future)
{
if (latch->trigger()) {
// Note that we don't bother checking if 'future' has been
@@ -1344,7 +1344,14 @@ void expired(
// if the future has been discarded and rather than hiding a
// non-deterministic bug we always call 'f' if the timer has
// expired.
- promise->associate(f(future));
+ Option<Future<T>> future = weak_future.get();
+ if (future.isSome()) {
+ promise->associate(f(future.get()));
+ } else {
+ // The original future may be out of scope, but the caller of
+ // after may still hold a reference to the promise's future.
+ promise->associate(f(promise->future()));
+ }
}
}
@@ -1435,19 +1442,21 @@ Future<T> Future<T>::after(
std::shared_ptr<Promise<T>> promise(new Promise<T>());
// Set up a timer to invoke the callback if this future has not
- // completed. Note that we do not pass a weak reference for this
- // future as we don't want the future to get cleaned up and then
- // have the timer expire.
+ // completed. A weak reference is needed to avoid memory leaks
+ // when storing the timer inside the future onAny callbacks vector.
+ // If the future has been cleaned, we use the `promise` future
+ // instead.
+ WeakFuture<T> weak_future(*this);
Timer timer = Clock::timer(
duration,
- lambda::bind(&internal::expired<T>, f, latch, promise, *this));
+ lambda::bind(&internal::expired<T>, f, latch, promise, weak_future));
onAny(lambda::bind(&internal::after<T>, latch, promise, timer, lambda::_1));
// Propagate discarding up the chain. To avoid cyclic dependencies,
// we keep a weak future in the callback.
promise->future().onDiscard(
- lambda::bind(&internal::discard<T>, WeakFuture<T>(*this)));
+ lambda::bind(&internal::discard<T>, weak_future));
return promise->future();
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/be127e6e/3rdparty/libprocess/src/tests/future_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/future_tests.cpp b/3rdparty/libprocess/src/tests/future_tests.cpp
index 7c411c7..fbf6995 100644
--- a/3rdparty/libprocess/src/tests/future_tests.cpp
+++ b/3rdparty/libprocess/src/tests/future_tests.cpp
@@ -18,6 +18,8 @@
#include <process/future.hpp>
#include <process/gtest.hpp>
+#include <stout/duration.hpp>
+#include <stout/nothing.hpp>
#include <stout/try.hpp>
using process::Clock;
@@ -256,6 +258,30 @@ TEST(FutureTest, After2)
}
+// Verifies that a a future does not leak memory after calling
+// `after()`. This behavior ocurred because a future indirectly
+// kept a reference counted pointer to itself.
+TEST(FutureTest, After3)
+{
+ Future<Nothing> future;
+ process::WeakFuture<Nothing> weak_future(future);
+
+ EXPECT_SOME(weak_future.get());
+
+ {
+ // The original future disappears here. After this call the
+ // original future goes out of scope and should not be reachable
+ // anymore.
+ future = future.after(
+ Milliseconds(1), [](const Future<Nothing>&) { return Nothing(); });
+
+ AWAIT_READY(future);
+ }
+
+ EXPECT_NONE(weak_future.get());
+}
+
+
static Future<bool> readyFuture()
{
return true;