Hazard pointers: Optimize memory order, add bulk reclamation control, add stats,...
[folly.git] / folly / experimental / hazptr / hazptr.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 #define HAZPTR_H
18
19 #include <atomic>
20 #include <functional>
21 #include <memory>
22 #include <type_traits>
23
24 /* Stand-in for C++17 std::pmr::memory_resource */
25 #include <folly/experimental/hazptr/memory_resource.h>
26
27 namespace folly {
28 namespace hazptr {
29
30 /** hazptr_rec: Private class that contains hazard pointers. */
31 class hazptr_rec;
32
33 /** hazptr_obj: Private class for objects protected by hazard pointers. */
34 class hazptr_obj;
35
36 /** hazptr_obj_base: Base template for objects protected by hazard pointers. */
37 template <typename T, typename Deleter>
38 class hazptr_obj_base;
39
40 /** hazptr_domain: Class of hazard pointer domains. Each domain manages a set
41  *  of hazard pointers and a set of retired objects. */
42 class hazptr_domain {
43  public:
44   constexpr explicit hazptr_domain(
45       memory_resource* = get_default_resource()) noexcept;
46   ~hazptr_domain();
47
48   hazptr_domain(const hazptr_domain&) = delete;
49   hazptr_domain(hazptr_domain&&) = delete;
50   hazptr_domain& operator=(const hazptr_domain&) = delete;
51   hazptr_domain& operator=(hazptr_domain&&) = delete;
52
53  private:
54   template <typename, typename>
55   friend class hazptr_obj_base;
56   template <typename>
57   friend class hazptr_owner;
58
59   memory_resource* mr_;
60   std::atomic<hazptr_rec*> hazptrs_ = {nullptr};
61   std::atomic<hazptr_obj*> retired_ = {nullptr};
62   std::atomic<int> hcount_ = {0};
63   std::atomic<int> rcount_ = {0};
64
65   void objRetire(hazptr_obj*);
66   hazptr_rec* hazptrAcquire();
67   void hazptrRelease(hazptr_rec*) noexcept;
68   int pushRetired(hazptr_obj* head, hazptr_obj* tail, int count);
69   void tryBulkReclaim();
70   void bulkReclaim();
71 };
72
73 /** Get the default hazptr_domain */
74 hazptr_domain& default_hazptr_domain();
75
76 /** Definition of hazptr_obj */
77 class hazptr_obj {
78   friend class hazptr_domain;
79   template <typename, typename>
80   friend class hazptr_obj_base;
81
82   void (*reclaim_)(hazptr_obj*);
83   hazptr_obj* next_;
84   const void* getObjPtr() const;
85 };
86
87 /** Definition of hazptr_obj_base */
88 template <typename T, typename Deleter = std::default_delete<T>>
89 class hazptr_obj_base : public hazptr_obj {
90  public:
91   /* Retire a removed object and pass the responsibility for
92    * reclaiming it to the hazptr library */
93   void retire(
94       hazptr_domain& domain = default_hazptr_domain(),
95       Deleter reclaim = {});
96
97  private:
98   Deleter deleter_;
99 };
100
101 /** hazptr_owner: Template for automatic acquisition and release of
102  *  hazard pointers, and interface for hazard pointer operations. */
103 template <typename T> class hazptr_owner {
104  public:
105   /* Constructor automatically acquires a hazard pointer. */
106   explicit hazptr_owner(hazptr_domain& domain = default_hazptr_domain());
107   /* Destructor automatically clears and releases the owned hazard pointer. */
108   ~hazptr_owner();
109
110   /* Copy and move constructors and assignment operators are
111    * disallowed because:
112    * - Each hazptr_owner owns exactly one hazard pointer at any time.
113    * - Each hazard pointer may have up to one owner at any time. */
114   hazptr_owner(const hazptr_owner&) = delete;
115   hazptr_owner(hazptr_owner&&) = delete;
116   hazptr_owner& operator=(const hazptr_owner&) = delete;
117   hazptr_owner& operator=(hazptr_owner&&) = delete;
118
119   /** Hazard pointer operations */
120   /* Returns a protected pointer from the source */
121   template <typename A = std::atomic<T*>>
122   T* get_protected(const A& src) noexcept;
123   /* Return true if successful in protecting ptr if src == ptr after
124    * setting the hazard pointer.  Otherwise sets ptr to src. */
125   template <typename A = std::atomic<T*>>
126   bool try_protect(T*& ptr, const A& src) noexcept;
127   /* Set the hazard pointer to ptr */
128   void set(const T* ptr) noexcept;
129   /* Clear the hazard pointer */
130   void clear() noexcept;
131
132   /* Swap ownership of hazard pointers between hazptr_owner-s. */
133   /* Note: The owned hazard pointers remain unmodified during the swap
134    * and continue to protect the respective objects that they were
135    * protecting before the swap, if any. */
136   void swap(hazptr_owner&) noexcept;
137
138  private:
139   hazptr_domain* domain_;
140   hazptr_rec* hazptr_;
141 };
142
143 template <typename T>
144 void swap(hazptr_owner<T>&, hazptr_owner<T>&) noexcept;
145
146 } // namespace hazptr
147 } // namespace folly
148
149 #include "hazptr-impl.h"