Commit 2f75edd3 authored by Kirk Shoop's avatar Kirk Shoop Committed by Facebook GitHub Bot

add support for adopting a shared_ptr

Summary:
When incrementally adding in MasterPtr to an existing code-base there are some shared_ptr<> (eg. returned from factories) that need to be stored in MasterPtr.

since unique_ptr converts to shared_ptr, just take and store a shared_ptr

Yes, this removes the guarantee that ~T() will run in join(). I am open to suggestions

Reviewed By: andriigrynenko

Differential Revision: D19583122

fbshipit-source-id: 3daf0436d56b9c396b5e82d397ebaf93ed1a2a2d
parent 1f5ce2de
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <folly/Function.h>
#include <folly/synchronization/Baton.h> #include <folly/synchronization/Baton.h>
#include <glog/logging.h> #include <glog/logging.h>
...@@ -89,7 +90,8 @@ class EnableMasterFromThis { ...@@ -89,7 +90,8 @@ class EnableMasterFromThis {
} }
private: private:
friend class MasterPtr<T>; template <class>
friend class MasterPtr;
std::weak_ptr<std::shared_ptr<T>> outerPtrWeak_; std::weak_ptr<std::shared_ptr<T>> outerPtrWeak_;
std::weak_ptr<T> lockedPtrWeak_; std::weak_ptr<T> lockedPtrWeak_;
...@@ -108,7 +110,8 @@ template <typename T> ...@@ -108,7 +110,8 @@ template <typename T>
class MasterPtr { class MasterPtr {
public: public:
MasterPtr() = delete; MasterPtr() = delete;
MasterPtr(std::unique_ptr<T> ptr) { template <class T2, class Deleter>
MasterPtr(std::unique_ptr<T2, Deleter> ptr) {
set(std::move(ptr)); set(std::move(ptr));
} }
~MasterPtr() { ~MasterPtr() {
...@@ -148,7 +151,8 @@ class MasterPtr { ...@@ -148,7 +151,8 @@ class MasterPtr {
// Sets the pointer. Can not be called concurrently with lock() or join() or // Sets the pointer. Can not be called concurrently with lock() or join() or
// ref(). // ref().
void set(std::unique_ptr<T> ptr) { template <class T2, class Deleter>
void set(std::unique_ptr<T2, Deleter> ptr) {
if (*this) { if (*this) {
LOG(FATAL) << "MasterPtr has to be joined before being set."; LOG(FATAL) << "MasterPtr has to be joined before being set.";
} }
...@@ -157,14 +161,17 @@ class MasterPtr { ...@@ -157,14 +161,17 @@ class MasterPtr {
return; return;
} }
innerPtr_ = std::move(ptr); auto rawPtr = ptr.get();
innerPtr_ = std::unique_ptr<T, folly::Function<void(T*)>>{
ptr.release(),
[d = ptr.get_deleter(), rawPtr](T*) mutable { d(rawPtr); }};
joinBaton_.reset(); joinBaton_.reset();
auto innerPtrShared = auto innerPtrShared =
std::shared_ptr<T>(innerPtr_.get(), [&](T*) { joinBaton_.post(); }); std::shared_ptr<T>(rawPtr, [&](T*) { joinBaton_.post(); });
outerPtrShared_ = outerPtrShared_ =
std::make_shared<std::shared_ptr<T>>(std::move(innerPtrShared)); std::make_shared<std::shared_ptr<T>>(std::move(innerPtrShared));
outerPtrWeak_ = outerPtrShared_; outerPtrWeak_ = outerPtrShared_;
EnableMasterFromThis<T>::set(innerPtr_.get(), outerPtrShared_); EnableMasterFromThis<T>::set(rawPtr, outerPtrShared_);
} }
// Gets a non-owning reference to the pointer. join() does *NOT* wait for // Gets a non-owning reference to the pointer. join() does *NOT* wait for
...@@ -175,22 +182,21 @@ class MasterPtr { ...@@ -175,22 +182,21 @@ class MasterPtr {
private: private:
friend class MasterPtrRef<T>; friend class MasterPtrRef<T>;
folly::Baton<> joinBaton_; folly::Baton<> joinBaton_;
std::shared_ptr<std::shared_ptr<T>> outerPtrShared_; std::shared_ptr<std::shared_ptr<T>> outerPtrShared_;
std::weak_ptr<std::shared_ptr<T>> outerPtrWeak_; std::weak_ptr<std::shared_ptr<T>> outerPtrWeak_;
std::unique_ptr<T> innerPtr_; std::unique_ptr<T, folly::Function<void(T*)>> innerPtr_;
}; };
/** /**
* MasterPtrRef is a non-owning reference to the pointer. MasterPtr::join() does * MasterPtrRef is a non-owning reference to the pointer. MasterPtr::join()
* *NOT* wait for outstanding MasterPtrRef objects to be released. * does *NOT* wait for outstanding MasterPtrRef objects to be released.
*/ */
template <typename T> template <typename T>
class MasterPtrRef { class MasterPtrRef {
public: public:
// Attempts to lock a pointer. Returns null if pointer is not set or if join() // Attempts to lock a pointer. Returns null if pointer is not set or if
// was called (even if the call to join() hasn't returned yet). // join() was called (even if the call to join() hasn't returned yet).
std::shared_ptr<T> lock() const { std::shared_ptr<T> lock() const {
if (auto outerPtr = outerPtrWeak_.lock()) { if (auto outerPtr = outerPtrWeak_.lock()) {
return *outerPtr; return *outerPtr;
...@@ -199,8 +205,10 @@ class MasterPtrRef { ...@@ -199,8 +205,10 @@ class MasterPtrRef {
} }
private: private:
friend class EnableMasterFromThis<T>; template <class>
friend class MasterPtr<T>; friend class EnableMasterFromThis;
template <class>
friend class MasterPtr;
/* implicit */ MasterPtrRef(std::weak_ptr<std::shared_ptr<T>> outerPtrWeak) /* implicit */ MasterPtrRef(std::weak_ptr<std::shared_ptr<T>> outerPtrWeak)
: outerPtrWeak_(std::move(outerPtrWeak)) {} : outerPtrWeak_(std::move(outerPtrWeak)) {}
......
...@@ -71,8 +71,10 @@ struct Mastered : folly::EnableMasterFromThis<Mastered> { ...@@ -71,8 +71,10 @@ struct Mastered : folly::EnableMasterFromThis<Mastered> {
} }
}; };
struct Derived : Mastered {};
TEST(MasterPtrTest, EnableMasterFromThis) { TEST(MasterPtrTest, EnableMasterFromThis) {
auto ptr = std::make_unique<Mastered>(); auto ptr = std::make_unique<Derived>();
auto rawPtr = ptr.get(); auto rawPtr = ptr.get();
auto masterPtr = folly::MasterPtr<Mastered>{std::move(ptr)}; auto masterPtr = folly::MasterPtr<Mastered>{std::move(ptr)};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment