adding a fibers compatible once flag
[folly.git] / folly / io / async / DelayedDestructionBase.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
17 #pragma once
18
19 #include <assert.h>
20 #include <cstddef>
21 #include <cstdint>
22 #include <functional>
23 #include <memory>
24 #include <type_traits>
25 #include <utility>
26
27 #include <boost/noncopyable.hpp>
28 #include <glog/logging.h>
29
30 namespace folly {
31
32 /**
33  * DelayedDestructionBase is a helper class to ensure objects are not deleted
34  * while they still have functions executing in a higher stack frame.
35  *
36  * This is useful for objects that invoke callback functions, to ensure that a
37  * callback does not destroy the calling object.
38  *
39  * Classes needing this functionality should:
40  * - derive from DelayedDestructionBase directly
41  * - implement onDelayedDestroy which'll be called before the object is
42  *   going to be destructed
43  * - create a DestructorGuard object on the stack in each public method that
44  *   may invoke a callback
45  *
46  * DelayedDestructionBase does not perform any locking.  It is intended to be
47  * used only from a single thread.
48  */
49 class DelayedDestructionBase : private boost::noncopyable {
50  public:
51   virtual ~DelayedDestructionBase() = default;
52
53   /**
54    * Classes should create a DestructorGuard object on the stack in any
55    * function that may invoke callback functions.
56    *
57    * The DestructorGuard prevents the guarded class from being destroyed while
58    * it exists.  Without this, the callback function could delete the guarded
59    * object, causing problems when the callback function returns and the
60    * guarded object's method resumes execution.
61    */
62   class DestructorGuard {
63    public:
64
65     explicit DestructorGuard(DelayedDestructionBase* dd = nullptr) :
66         dd_(dd) {
67       if (dd_ != nullptr) {
68         ++dd_->guardCount_;
69         assert(dd_->guardCount_ > 0); // check for wrapping
70       }
71     }
72
73     DestructorGuard(const DestructorGuard& dg) :
74         DestructorGuard(dg.dd_) {
75     }
76
77     DestructorGuard(DestructorGuard&& dg) noexcept :
78         dd_(dg.dd_) {
79       dg.dd_ = nullptr;
80     }
81
82     DestructorGuard& operator =(DestructorGuard dg) noexcept {
83       std::swap(dd_, dg.dd_);
84       return *this;
85     }
86
87     DestructorGuard& operator =(DelayedDestructionBase* dd) {
88       *this = DestructorGuard(dd);
89       return *this;
90     }
91
92     ~DestructorGuard() {
93       if (dd_ != nullptr) {
94         assert(dd_->guardCount_ > 0);
95         --dd_->guardCount_;
96         if (dd_->guardCount_ == 0) {
97           dd_->onDelayedDestroy(true);
98         }
99       }
100     }
101
102     DelayedDestructionBase* get() const {
103       return dd_;
104     }
105
106     explicit operator bool() const {
107       return dd_ != nullptr;
108     }
109
110    private:
111     DelayedDestructionBase* dd_;
112   };
113
114   /**
115    * This smart pointer is a convenient way to manage a concrete
116    * DelayedDestructorBase child. It can replace the equivalent raw pointer and
117    * provide automatic memory management.
118    */
119   template <typename AliasType>
120   class IntrusivePtr : private DestructorGuard {
121     template <typename CopyAliasType>
122     friend class IntrusivePtr;
123    public:
124     template <typename... Args>
125     static IntrusivePtr<AliasType> make(Args&&... args) {
126       return {new AliasType(std::forward<Args>(args)...)};
127     }
128
129     IntrusivePtr() = default;
130     IntrusivePtr(const IntrusivePtr&) = default;
131     IntrusivePtr(IntrusivePtr&&) noexcept = default;
132
133     template <typename CopyAliasType, typename =
134       typename std::enable_if<
135         std::is_convertible<CopyAliasType*, AliasType*>::value
136       >::type>
137     IntrusivePtr(const IntrusivePtr<CopyAliasType>& copy) :
138         DestructorGuard(copy) {
139     }
140
141     template <typename CopyAliasType, typename =
142       typename std::enable_if<
143         std::is_convertible<CopyAliasType*, AliasType*>::value
144       >::type>
145     IntrusivePtr(IntrusivePtr<CopyAliasType>&& copy) :
146         DestructorGuard(std::move(copy)) {
147     }
148
149     explicit IntrusivePtr(AliasType* dd) :
150         DestructorGuard(dd) {
151     }
152
153     // Copying from a unique_ptr is safe because if the upcast to
154     // DelayedDestructionBase works, then the instance is already using
155     // intrusive ref-counting.
156     template <typename CopyAliasType, typename Deleter, typename =
157       typename std::enable_if<
158         std::is_convertible<CopyAliasType*, AliasType*>::value
159       >::type>
160     explicit IntrusivePtr(const std::unique_ptr<CopyAliasType, Deleter>& copy) :
161         DestructorGuard(copy.get()) {
162     }
163
164     IntrusivePtr& operator =(const IntrusivePtr&) = default;
165     IntrusivePtr& operator =(IntrusivePtr&&) noexcept = default;
166
167     template <typename CopyAliasType, typename =
168       typename std::enable_if<
169         std::is_convertible<CopyAliasType*, AliasType*>::value
170       >::type>
171     IntrusivePtr& operator =(IntrusivePtr<CopyAliasType> copy) noexcept {
172       DestructorGuard::operator =(copy);
173       return *this;
174     }
175
176     IntrusivePtr& operator =(AliasType* dd) {
177       DestructorGuard::operator =(dd);
178       return *this;
179     }
180
181     void reset(AliasType* dd = nullptr) {
182       *this = dd;
183     }
184
185     AliasType* get() const {
186       return static_cast<AliasType *>(DestructorGuard::get());
187     }
188
189     AliasType& operator *() const {
190       return *get();
191     }
192
193     AliasType* operator ->() const {
194       return get();
195     }
196
197     explicit operator bool() const {
198       return DestructorGuard::operator bool();
199     }
200   };
201
202  protected:
203   DelayedDestructionBase()
204     : guardCount_(0) {}
205
206   /**
207    * Get the number of DestructorGuards currently protecting this object.
208    *
209    * This is primarily intended for debugging purposes, such as asserting
210    * that an object has at least 1 guard.
211    */
212   uint32_t getDestructorGuardCount() const {
213     return guardCount_;
214   }
215
216   /**
217    * Implement onDelayedDestroy in subclasses.
218    * onDelayedDestroy() is invoked when the object is potentially being
219    * destroyed.
220    *
221    * @param delayed  This parameter is true if destruction was delayed because
222    *                 of a DestructorGuard object, or false if onDelayedDestroy()
223    *                 is being called directly from the destructor.
224    */
225   virtual void onDelayedDestroy(bool delayed) = 0;
226
227  private:
228   /**
229    * guardCount_ is incremented by DestructorGuard, to indicate that one of
230    * the DelayedDestructionBase object's methods is currently running.
231    *
232    * If the destructor is called while guardCount_ is non-zero, destruction
233    * will be delayed until guardCount_ drops to 0.  This allows
234    * DelayedDestructionBase objects to invoke callbacks without having to worry
235    * about being deleted before the callback returns.
236    */
237   uint32_t guardCount_;
238 };
239
240 inline bool operator ==(
241     const DelayedDestructionBase::DestructorGuard& left,
242     const DelayedDestructionBase::DestructorGuard& right) {
243   return left.get() == right.get();
244 }
245 inline bool operator !=(
246     const DelayedDestructionBase::DestructorGuard& left,
247     const DelayedDestructionBase::DestructorGuard& right) {
248   return left.get() != right.get();
249 }
250 inline bool operator ==(
251     const DelayedDestructionBase::DestructorGuard& left,
252     std::nullptr_t right) {
253   return left.get() == right;
254 }
255 inline bool operator ==(
256     std::nullptr_t left,
257     const DelayedDestructionBase::DestructorGuard& right) {
258   return left == right.get();
259 }
260 inline bool operator !=(
261     const DelayedDestructionBase::DestructorGuard& left,
262     std::nullptr_t right) {
263   return left.get() != right;
264 }
265 inline bool operator !=(
266     std::nullptr_t left,
267     const DelayedDestructionBase::DestructorGuard& right) {
268   return left != right.get();
269 }
270
271 template <typename LeftAliasType, typename RightAliasType>
272 inline bool operator ==(
273     const DelayedDestructionBase::IntrusivePtr<LeftAliasType>& left,
274     const DelayedDestructionBase::IntrusivePtr<RightAliasType>& right) {
275   return left.get() == right.get();
276 }
277 template <typename LeftAliasType, typename RightAliasType>
278 inline bool operator !=(
279     const DelayedDestructionBase::IntrusivePtr<LeftAliasType>& left,
280     const DelayedDestructionBase::IntrusivePtr<RightAliasType>& right) {
281   return left.get() != right.get();
282 }
283 template <typename LeftAliasType>
284 inline bool operator ==(
285     const DelayedDestructionBase::IntrusivePtr<LeftAliasType>& left,
286     std::nullptr_t right) {
287   return left.get() == right;
288 }
289 template <typename RightAliasType>
290 inline bool operator ==(
291     std::nullptr_t left,
292     const DelayedDestructionBase::IntrusivePtr<RightAliasType>& right) {
293   return left == right.get();
294 }
295 template <typename LeftAliasType>
296 inline bool operator !=(
297     const DelayedDestructionBase::IntrusivePtr<LeftAliasType>& left,
298     std::nullptr_t right) {
299   return left.get() != right;
300 }
301 template <typename RightAliasType>
302 inline bool operator !=(
303     std::nullptr_t left,
304     const DelayedDestructionBase::IntrusivePtr<RightAliasType>& right) {
305   return left != right.get();
306 }
307 } // namespace folly