diff options
author | Mathias Stearn <mathias@10gen.com> | 2019-04-17 19:08:42 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2019-04-18 14:02:32 -0400 |
commit | b53170282d1e314549350d7124830a2457bad5d6 (patch) | |
tree | 131ce1fa9b30cf6d05093c7d053521e6d680b27c /src/mongo/util/future.h | |
parent | 6569889b76f44f8c5bf39c2743b77c6716fb30bf (diff) | |
download | mongo-b53170282d1e314549350d7124830a2457bad5d6.tar.gz |
SERVER-36359 Non-ready Futures don't actually complete SharedPromises
Diffstat (limited to 'src/mongo/util/future.h')
-rw-r--r-- | src/mongo/util/future.h | 25 |
1 files changed, 11 insertions, 14 deletions
diff --git a/src/mongo/util/future.h b/src/mongo/util/future.h index f0a5b8ad990..ca203162003 100644 --- a/src/mongo/util/future.h +++ b/src/mongo/util/future.h @@ -252,6 +252,7 @@ public: private: friend class Promise<T>; + friend class SharedPromise<T>; template <typename> friend class Future; template <typename> @@ -501,6 +502,7 @@ private: template <typename> friend class future_details::FutureImpl; friend class Promise<T>; + friend class SharedPromise<T>; using SemiFuture<T>::unsafeToInlineFuture; @@ -994,7 +996,7 @@ public: SharedPromise() = default; ~SharedPromise() { - if (MONGO_unlikely(!haveCompleted())) { + if (MONGO_unlikely(!_haveCompleted)) { _sharedState->setError({ErrorCodes::BrokenPromise, "broken promise"}); } } @@ -1014,44 +1016,39 @@ public: template <typename Func> void setWith(Func&& func) noexcept { - invariant(!haveCompleted()); + invariant(!std::exchange(_haveCompleted, true)); setFrom(Future<void>::makeReady().then(std::forward<Func>(func))); } void setFrom(Future<T>&& future) noexcept { - invariant(!haveCompleted()); + invariant(!std::exchange(_haveCompleted, true)); std::move(future).propagateResultTo(_sharedState.get()); } template <typename... Args> void emplaceValue(Args&&... args) noexcept { - invariant(!haveCompleted()); + invariant(!std::exchange(_haveCompleted, true)); _sharedState->emplaceValue(std::forward<Args>(args)...); } void setError(Status status) noexcept { invariant(!status.isOK()); - invariant(!haveCompleted()); + invariant(!std::exchange(_haveCompleted, true)); _sharedState->setError(std::move(status)); } // TODO rename to not XXXWith and handle void void setFromStatusWith(StatusWith<T> sw) noexcept { - invariant(!haveCompleted()); + invariant(!std::exchange(_haveCompleted, true)); _sharedState->setFromStatusWith(std::move(sw)); } private: friend class Future<void>; - bool haveCompleted() const noexcept { - // This can be relaxed because it is only called from the Promise thread which is also the - // only thread that will transition this from returning false to true. Additionally it isn't - // used to establish synchronization with any other thread. - return _sharedState->state.load(std::memory_order_relaxed) == - future_details::SSBState::kFinished; - } - + // This is slightly different from whether the SharedState is in kFinished, because this + // SharedPromise may have been completed with a Future that isn't ready yet. + bool _haveCompleted = false; const boost::intrusive_ptr<future_details::SharedState<T>> _sharedState = make_intrusive<future_details::SharedState<T>>(); }; |