X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2Fexperimental%2Fhazptr%2Fhazptr.h;h=48e8392ae48676fccd311e667e41e0f986ca2117;hp=456fa6c4b7816cd56c94f78b9ba9546e489430fb;hb=7046d43c7e3c18ebc28c62141b8e1eefabce5323;hpb=520148aaf14ab535b386c045e836af47645436ff diff --git a/folly/experimental/hazptr/hazptr.h b/folly/experimental/hazptr/hazptr.h index 456fa6c4..48e8392a 100644 --- a/folly/experimental/hazptr/hazptr.h +++ b/folly/experimental/hazptr/hazptr.h @@ -34,6 +34,21 @@ class hazptr_obj; template class hazptr_obj_base; +/** hazptr_obj_base_refcounted: + * Base template for reference counted objects protected by hazard pointers. + */ +template +class hazptr_obj_base_refcounted; + +/** hazptr_local: Optimized template for bulk construction and destruction of + * hazard pointers */ +template +class hazptr_array; + +/** hazptr_local: Optimized template for locally-used hazard pointers */ +template +class hazptr_local; + /** hazptr_domain: Class of hazard pointer domains. Each domain manages a set * of hazard pointers and a set of retired objects. */ class hazptr_domain { @@ -47,10 +62,16 @@ class hazptr_domain { hazptr_domain& operator=(const hazptr_domain&) = delete; hazptr_domain& operator=(hazptr_domain&&) = delete; + /** Free-function retire. May allocate memory */ + template > + void retire(T* obj, D reclaim = {}); + private: friend class hazptr_holder; template friend class hazptr_obj_base; + template + friend class hazptr_obj_base_refcounted; friend struct hazptr_priv; memory_resource* mr_; @@ -73,15 +94,22 @@ hazptr_domain& default_hazptr_domain(); extern hazptr_domain default_domain_; +/** Free-function retire, that operates on the default domain */ +template > +void hazptr_retire(T* obj, D reclaim = {}); + /** Definition of hazptr_obj */ class hazptr_obj { friend class hazptr_domain; template friend class hazptr_obj_base; + template + friend class hazptr_obj_base_refcounted; friend struct hazptr_priv; void (*reclaim_)(hazptr_obj*); hazptr_obj* next_; + const void* getObjPtr() const; }; @@ -97,15 +125,47 @@ class hazptr_obj_base : public hazptr_obj { D deleter_; }; +/** Definition of hazptr_recounted_obj_base */ +template > +class hazptr_obj_base_refcounted : public hazptr_obj { + public: + /* Retire a removed object and pass the responsibility for + * reclaiming it to the hazptr library */ + void retire(hazptr_domain& domain = default_hazptr_domain(), D reclaim = {}); + + /* aquire_ref() increments the reference count + * + * acquire_ref_safe() is the same as acquire_ref() except that in + * addition the caller guarantees that the call is made in a + * thread-safe context, e.g., the object is not yet shared. This is + * just an optimization to save an atomic operation. + * + * release_ref() decrements the reference count and returns true if + * the object is safe to reclaim. + */ + void acquire_ref(); + void acquire_ref_safe(); + bool release_ref(); + + private: + std::atomic refcount_{0}; + D deleter_; +}; + /** hazptr_holder: Class for automatic acquisition and release of * hazard pointers, and interface for hazard pointer operations. */ class hazptr_holder { + template + friend class hazptr_array; + template + friend class hazptr_local; + public: /* Constructor automatically acquires a hazard pointer. */ explicit hazptr_holder(hazptr_domain& domain = default_hazptr_domain()); /* Construct an empty hazptr_holder. */ // Note: This diverges from the proposal in P0233R4 - explicit hazptr_holder(std::nullptr_t); + explicit hazptr_holder(std::nullptr_t) noexcept; /* Destructor automatically clears and releases the owned hazard pointer. */ ~hazptr_holder(); @@ -154,6 +214,69 @@ class hazptr_holder { void swap(hazptr_holder&, hazptr_holder&) noexcept; +using aligned_hazptr_holder = typename std:: + aligned_storage::type; + +/** + * hazptr_array: Optimized for bulk construction and destruction of + * hazptr_holder-s. + * + * WARNING: Do not move from or to individual hazptr_holder-s. + * Only move the whole hazptr_array. + */ +template +class hazptr_array { + static_assert(M > 0, "M must be a positive integer."); + + public: + hazptr_array(); + explicit hazptr_array(std::nullptr_t) noexcept; + + hazptr_array(const hazptr_array&) = delete; + hazptr_array& operator=(const hazptr_array&) = delete; + hazptr_array(hazptr_array&& other) noexcept; + hazptr_array& operator=(hazptr_array&& other) noexcept; + + ~hazptr_array(); + + hazptr_holder& operator[](size_t i) noexcept; + + private: + aligned_hazptr_holder raw_[M]; + bool empty_{false}; +}; + +/** + * hazptr_local: Optimized for construction and destruction of + * one or more hazptr_holder-s with local scope. + * + * WARNING 1: Do not move from or to individual hazptr_holder-s. + * + * WARNING 2: There can only be one hazptr_local active for the same + * thread at any time. This is not tracked and checked by the + * implementation because it would negate the performance gains of + * this class. + */ +template +class hazptr_local { + static_assert(M > 0, "M must be a positive integer."); + + public: + hazptr_local(); + hazptr_local(const hazptr_local&) = delete; + hazptr_local& operator=(const hazptr_local&) = delete; + hazptr_local(hazptr_local&&) = delete; + hazptr_local& operator=(hazptr_local&&) = delete; + + ~hazptr_local(); + + hazptr_holder& operator[](size_t i) noexcept; + + private: + aligned_hazptr_holder raw_[M]; + bool need_destruct_{false}; +}; + } // namespace hazptr } // namespace folly