Update hazard pointers prototype
[folly.git] / folly / experimental / hazptr / hazptr.h
1 /*
2  * Copyright 2016 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
23 /* Stand-in for std::pmr::memory_resource */
24 #include <folly/experimental/hazptr/memory_resource.h>
25
26 namespace folly {
27 namespace hazptr {
28
29 /** hazptr_rec: Private class that contains hazard pointers. */
30 class hazptr_rec;
31
32 /** hazptr_obj: Private class for objects protected by hazard pointers. */
33 class hazptr_obj;
34
35 /** hazptr_obj_base: Base template for objects protected by hazard pointers. */
36 template <typename T, typename Deleter>
37 class hazptr_obj_base;
38
39 /** hazptr_domain: Class of hazard pointer domains. Each domain manages a set
40  *  of hazard pointers and a set of retired objects. */
41 class hazptr_domain {
42  public:
43   constexpr explicit hazptr_domain(
44       memory_resource* = get_default_resource()) noexcept;
45   ~hazptr_domain();
46
47   hazptr_domain(const hazptr_domain&) = delete;
48   hazptr_domain(hazptr_domain&&) = delete;
49   hazptr_domain& operator=(const hazptr_domain&) = delete;
50   hazptr_domain& operator=(hazptr_domain&&) = delete;
51
52   void try_reclaim();
53
54  private:
55   template <typename, typename>
56   friend class hazptr_obj_base;
57   template <typename> friend class hazptr_owner;
58
59   /** Constant -- May be changed to parameter in the future */
60   enum { kScanThreshold = 3 };
61
62   memory_resource* mr_;
63   std::atomic<hazptr_rec*> hazptrs_ = {nullptr};
64   std::atomic<hazptr_obj*> retired_ = {nullptr};
65   std::atomic<int> hcount_ = {0};
66   std::atomic<int> rcount_ = {0};
67
68   void objRetire(hazptr_obj*);
69   hazptr_rec* hazptrAcquire();
70   void hazptrRelease(hazptr_rec*) noexcept;
71   int pushRetired(hazptr_obj* head, hazptr_obj* tail, int count);
72   void tryBulkReclaim();
73   void bulkReclaim();
74 };
75
76 /** Get the default hazptr_domain */
77 hazptr_domain& default_hazptr_domain();
78
79 /** Definition of hazptr_obj */
80 class hazptr_obj {
81   friend class hazptr_domain;
82   template <typename, typename>
83   friend class hazptr_obj_base;
84
85   void (*reclaim_)(hazptr_obj*);
86   hazptr_obj* next_;
87   const void* getObjPtr() const;
88 };
89
90 /** Definition of hazptr_obj_base */
91 template <typename T, typename Deleter = std::default_delete<T>>
92 class hazptr_obj_base : private hazptr_obj {
93  public:
94   /* Policy for storing retired objects */
95   enum class storage_policy { priv, shared };
96
97   /* Retire a removed object and pass the responsibility for
98    * reclaiming it to the hazptr library */
99   void retire(
100       hazptr_domain& domain = default_hazptr_domain(),
101       Deleter reclaim = {},
102       const storage_policy policy = storage_policy::shared);
103
104  private:
105   Deleter deleter_;
106 };
107
108 /** hazptr_owner: Template for automatic acquisition and release of
109  *  hazard pointers, and interface for hazard pointer operations. */
110 template <typename T> class hazptr_owner {
111  public:
112   /* Policy for caching hazard pointers */
113   enum class cache_policy { cache, nocache };
114
115   /* Constructor automatically acquires a hazard pointer. */
116   explicit hazptr_owner(
117       hazptr_domain& domain = default_hazptr_domain(),
118       const cache_policy policy = cache_policy::nocache);
119
120   /* Destructor automatically clears and releases the owned hazard pointer. */
121   ~hazptr_owner();
122
123   /* Copy and move constructors and assignment operators are
124    * disallowed because:
125    * - Each hazptr_owner owns exactly one hazard pointer at any time.
126    * - Each hazard pointer may have up to one owner at any time. */
127   hazptr_owner(const hazptr_owner&) = delete;
128   hazptr_owner(hazptr_owner&&) = delete;
129   hazptr_owner& operator=(const hazptr_owner&) = delete;
130   hazptr_owner& operator=(hazptr_owner&&) = delete;
131
132   /** Hazard pointer operations */
133   /* Returns a protected pointer from the source */
134   T* get_protected(const std::atomic<T*>& src) noexcept;
135   /* Return true if successful in protecting ptr if src == ptr after
136    * setting the hazard pointer.  Otherwise sets ptr to src. */
137   bool try_protect(T*& ptr, const std::atomic<T*>& src) noexcept;
138   /* Set the hazard pointer to ptr */
139   void set(const T* ptr) noexcept;
140   /* Clear the hazard pointer */
141   void clear() noexcept;
142
143   /* Swap ownership of hazard ponters between hazptr_owner-s. */
144   /* Note: The owned hazard pointers remain unmodified during the swap
145    * and continue to protect the respective objects that they were
146    * protecting before the swap, if any. */
147   void swap(hazptr_owner&) noexcept;
148
149  private:
150   hazptr_domain* domain_;
151   hazptr_rec* hazptr_;
152 };
153
154 template <typename T>
155 void swap(hazptr_owner<T>&, hazptr_owner<T>&) noexcept;
156
157 /** hazptr_user: Thread-specific interface for users of hazard
158  *  pointers (i.e., threads that own hazard pointers by using
159  *  hazptr_owner. */
160 class hazptr_user {
161  public:
162   /* Release all hazptr_rec-s cached by this thread */
163   static void flush();
164 };
165
166 /** hazptr_remover: Thread-specific interface for removers of objects
167  *  protected by hazard pointersd, i.e., threads that call the retire
168  *  member function of hazptr_obj_base. */
169 class hazptr_remover {
170  public:
171   /* Pass responsibility of reclaiming any retired objects stored
172    * privately by this thread to the hazptr_domain to which they
173    * belong. */
174   static void flush();
175 };
176
177 } // namespace hazptr
178 } // namespace folly
179
180 ////////////////////////////////////////////////////////////////////////////////
181 /// Notes
182 ////////////////////////////////////////////////////////////////////////////////
183
184 /* The hazptr_obj_base template uses a reclamation function as a
185  * parameter for the retire() member function instead of taking an
186  * allocator template as an extra template parameter because objects
187  * of the same type may need different reclamation functions. */
188
189 /* The hazptr interface supports reclamation by one domain at a
190  * time. If an abject belongs to multiple domains simultaneously, a
191  * workaround may be to design reclamation functions to form a series
192  * of retirements from one domain to the next until it reaches the
193  * final domain in the series that finally reclaims the object. */
194
195 ////////////////////////////////////////////////////////////////////////////////
196
197 #include "hazptr-impl.h"