verdnatura-chat/ios/Pods/Flipper-Folly/folly/synchronization/Hazptr.h

216 lines
9.8 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/synchronization/Hazptr-fwd.h>
#include <folly/synchronization/HazptrDomain.h>
#include <folly/synchronization/HazptrHolder.h>
#include <folly/synchronization/HazptrObj.h>
#include <folly/synchronization/HazptrObjLinked.h>
#include <folly/synchronization/HazptrRec.h>
#include <folly/synchronization/HazptrThrLocal.h>
/// Hazard pointers is a safe reclamation method. It protects objects
/// from being reclaimed while being accessed by one or more threads, but
/// allows objects to be removed concurrently while being accessed.
///
/// What is a Hazard Pointer?
/// -------------------------
/// A hazard pointer is a single-writer multi-reader pointer that can
/// be owned by at most one thread at a time. To protect an object A
/// from being reclaimed while in use, a thread X sets one of its
/// owned hazard pointers, P, to the address of A. If P is set to &A
/// before A is removed (i.e., it becomes unreachable) then A will not be
/// reclaimed as long as P continues to hold the value &A.
///
/// Why use hazard pointers?
/// ------------------------
/// - Speed and scalability.
/// - Can be used while blocking.
///
/// When not to use hazard pointers?
/// --------------------------------
/// - When thread local data is not supported efficiently.
///
/// Basic Interface
/// ---------------
/// - In the hazptr library, raw hazard pointers are not exposed to
/// users. Instead, each instance of the class hazptr_holder owns
/// and manages at most one hazard pointer.
/// - Typically classes of objects protected by hazard pointers are
/// derived from a class template hazptr_obj_base that provides a
/// member function retire(). When an object A is removed,
/// A.retire() is called to pass responsibility for reclaiming A to
/// the hazptr library. A will be reclaimed only after it is not
/// protected by hazard pointers.
/// - The essential components of the hazptr API are:
/// o hazptr_holder: Class that owns and manages a hazard pointer.
/// o get_protected: Mmember function of hazptr_holder. Protects
/// an object pointed to by an atomic source (if not null).
/// T* get_protected(const atomic<T*>& src);
/// o hazptr_obj_base<T>: Base class for protected objects.
/// o retire: Member function of hazptr_obj_base that automatically
/// reclaims the object when safe.
/// void retire();
///
/// Default Domain and Default Deleters
/// -----------------------------------
/// - Most uses do not need to specify custom domains and custom
/// deleters, and by default use the default domain and default
/// deleters.
///
/// Simple usage example
/// --------------------
/// class Config : public hazptr_obj_base<Config> {
/// /* ... details ... */
/// U get_config(V v);
/// };
///
/// std::atomic<Config*> config_;
///
/// // Called frequently
/// U get_config(V v) {
/// hazptr_holder h; /* h owns a hazard pointer */
/// Config* ptr = h.get_protected(config_);
/// /* safe to access *ptr as long as it is protected by h */
/// return ptr->get_config(v);
/// /* h dtor resets and releases the owned hazard pointer,
/// *ptr will be no longer protected by this hazard pointer */
/// }
///
/// // called rarely
/// void update_config(Config* new_config) {
/// Config* ptr = config_.exchange(new_config);
/// ptr->retire() // Member function of hazptr_obj_base<Config>
/// }
///
/// Optimized Holders
/// -----------------
/// - The template hazptr_array<M> provides most of the functionality
/// of M hazptr_holder-s but with faster construction/destruction
/// (for M > 1), at the cost of restrictions (on move and swap).
/// - The template hazptr_local<M> provides greater speed even when
/// M=1 (~2 ns vs ~5 ns for construction/destruction) but it is
/// unsafe for the current thread to construct any other holder-type
/// objects (hazptr_holder, hazptr_array and other hazptr_local)
/// while the current instance exists.
/// - In the above example, if Config::get_config() and all of its
/// descendants are guaranteed not to use hazard pointers, then it
/// can be faster (by ~3 ns.) to use
/// hazptr_local<1> h;
/// Config* ptr = h[0].get_protected(config_);
/// than
/// hazptr_holder h;
/// Config* ptr = h.get_protected(config_);
///
/// Memory Usage
/// ------------
/// - The size of the metadata for the hazptr library is linear in the
/// number of threads using hazard pointers, assuming a constant
/// number of hazard pointers per thread, which is typical.
/// - The typical number of reclaimable but not yet reclaimed of
/// objects is linear in the number of hazard pointers, which
/// typically is linear in the number of threads using hazard
/// pointers.
///
/// Protecting Linked Structures and Automatic Retirement
/// -----------------------------------------------------
/// Hazard pointers provide link counting API to protect linked
/// structures. It is capable of automatic retirement of objects even
/// when the removal of objects is uncertain. It also supports
/// optimizations when links are known to be immutable. All the link
/// counting features incur no extra overhead for readers.
/// See HazptrObjLinked.h for more details.
///
/// Alternative Safe Reclamation Methods
/// ------------------------------------
/// - Locking (exclusive or shared):
/// o Pros: simple to reason about.
/// o Cons: serialization, high reader overhead, high contention, deadlock.
/// o When to use: When speed and contention are not critical, and
/// when deadlock avoidance is simple.
/// - Reference counting (atomic shared_ptr):
/// o Pros: automatic reclamation, thread-anonymous, independent of
/// support for thread local data, immune to deadlock.
/// o Cons: high reader (and writer) overhead, high reader (and
/// writer) contention.
/// o When to use: When thread local support is lacking and deadlock
/// can be a problem, or automatic reclamation is needed.
/// - Read-copy-update (RCU):
/// o Pros: simple, fast, scalable.
/// o Cons: sensitive to blocking
/// o When to use: When speed and scalability are important and
/// objects do not need to be protected while blocking.
///
/// Hazard Pointers vs RCU
/// ----------------------
/// - The differences between hazard pointers and RCU boil down to
/// that hazard pointers protect specific objects, whereas RCU
/// sections protect all protectable objects.
/// - Both have comparably low overheads for protection (i.e. reading
/// or traversal) in the order of low nanoseconds.
/// - Both support effectively perfect scalability of object
/// protection by read-only operations (barring other factors).
/// - Both rely on thread local data for performance.
/// - Hazard pointers can protect objects while blocking
/// indefinitely. Hazard pointers only prevent the reclamation of
/// the objects they are protecting.
/// - RCU sections do not allow indefinite blocking, because RCU
/// prevents the reclamation of all protectable objects, which
/// otherwise would lead to deadlock and/or running out of memory.
/// - Hazard pointers can support end-to-end lock-free operations,
/// including updates (provided lock-free allocator), regardless of
/// thread delays and scheduling constraints.
/// - RCU can support wait-free read operations, but reclamation of
/// unbounded objects can be delayed for as long as a single thread
/// is delayed.
/// - The number of unreclaimed objects is bounded when protected by
/// hazard pointers, but is unbounded when protected by RCU.
/// - RCU is simpler to use than hazard pointers (except for the
/// blocking and deadlock issues mentioned above). Hazard pointers
/// need to identify protected objects, whereas RCU does not need to
/// because it protects all protectable objects.
/// - Both can protect linked structures. Hazard pointers needs
/// additional link counting with low or moderate overhead for
/// update operations, and no overhead for readers. RCU protects
/// protects linked structures automatically, because it protects
/// everything.
///
/// Differences from the Standard Proposal
/// --------------------------------------
/// - The latest standard proposal is in wg21.link/p0566.
/// - This library's API differs from the standard proposal because:
/// (a) the standard proposal is changing based on committee
/// feedback, and (b) this library provides additional
/// fast-evolving features based on usage experience that do not
/// have corressponding proposed standard wording.
/// - The main differences are:
/// o This library uses an extra atomic template parameter for
/// testing and debugging.
/// o This library does not support a custom polymorphic allocator
/// (C++17) parameter for the hazptr_domain constructor, until
/// such support becomes widely available.
/// o The construction of empty and non-empty hazptr_holder-s are
/// reversed. This library will conform eventually.
/// o hazptr_holder member functions get_protected and reset are
/// called protect and reset_protected, respectively, in the
/// latest proposal. Will conform eventually.
/// o hazptr_array and hazptr_local are not part of the standard
/// proposal.
/// o Link counting support and protection of linked structures is
/// not part of the current standard proposal.