HazptrObj.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright 2018-present 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. #include <folly/synchronization/Hazptr-fwd.h>
  18. #include <folly/CPortability.h>
  19. #include <folly/Portability.h>
  20. #include <glog/logging.h>
  21. #include <atomic>
  22. #include <memory>
  23. ///
  24. /// Classes related to objects protected by hazard pointers.
  25. ///
  26. namespace folly {
  27. /**
  28. * hazptr_obj
  29. *
  30. * Object protected by hazard pointers.
  31. */
  32. template <template <typename> class Atom>
  33. class hazptr_obj {
  34. using ReclaimFnPtr = void (*)(hazptr_obj<Atom>*, hazptr_obj_list<Atom>&);
  35. template <template <typename> class>
  36. friend class hazptr_domain;
  37. template <typename, template <typename> class, typename>
  38. friend class hazptr_obj_base;
  39. template <typename, template <typename> class, typename>
  40. friend class hazptr_obj_base_linked;
  41. template <template <typename> class>
  42. friend class hazptr_obj_list;
  43. template <template <typename> class>
  44. friend class hazptr_priv;
  45. ReclaimFnPtr reclaim_;
  46. hazptr_obj<Atom>* next_;
  47. public:
  48. /** Constructors */
  49. /* All constructors set next_ to this in order to catch misuse bugs
  50. such as double retire. */
  51. hazptr_obj() noexcept : next_(this) {}
  52. hazptr_obj(const hazptr_obj<Atom>&) noexcept : next_(this) {}
  53. hazptr_obj(hazptr_obj<Atom>&&) noexcept : next_(this) {}
  54. /** Copy operator */
  55. hazptr_obj<Atom>& operator=(const hazptr_obj<Atom>&) noexcept {
  56. return *this;
  57. }
  58. /** Move operator */
  59. hazptr_obj<Atom>& operator=(hazptr_obj<Atom>&&) noexcept {
  60. return *this;
  61. }
  62. private:
  63. friend class hazptr_domain<Atom>;
  64. template <typename, template <typename> class, typename>
  65. friend class hazptr_obj_base;
  66. template <typename, template <typename> class, typename>
  67. friend class hazptr_obj_base_refcounted;
  68. friend class hazptr_priv<Atom>;
  69. hazptr_obj<Atom>* next() const noexcept {
  70. return next_;
  71. }
  72. void set_next(hazptr_obj* obj) noexcept {
  73. next_ = obj;
  74. }
  75. ReclaimFnPtr reclaim() noexcept {
  76. return reclaim_;
  77. }
  78. const void* raw_ptr() const {
  79. return this;
  80. }
  81. void pre_retire_check() noexcept {
  82. // Only for catching misuse bugs like double retire
  83. if (next_ != this) {
  84. pre_retire_check_fail();
  85. }
  86. }
  87. void push_to_retired(hazptr_domain<Atom>& domain) {
  88. #if FOLLY_HAZPTR_THR_LOCAL
  89. if (&domain == &default_hazptr_domain<Atom>() && !domain.shutdown_) {
  90. hazptr_priv_tls<Atom>().push(this);
  91. return;
  92. }
  93. #endif
  94. hazptr_obj_list<Atom> l(this);
  95. hazptr_domain_push_retired(l, true, domain);
  96. }
  97. FOLLY_NOINLINE void pre_retire_check_fail() noexcept {
  98. CHECK_EQ(next_, this);
  99. }
  100. }; // hazptr_obj
  101. /**
  102. * hazptr_obj_list
  103. *
  104. * List of hazptr_obj-s.
  105. */
  106. template <template <typename> class Atom>
  107. class hazptr_obj_list {
  108. hazptr_obj<Atom>* head_;
  109. hazptr_obj<Atom>* tail_;
  110. int count_;
  111. public:
  112. hazptr_obj_list() noexcept : head_(nullptr), tail_(nullptr), count_(0) {}
  113. explicit hazptr_obj_list(hazptr_obj<Atom>* obj) noexcept
  114. : head_(obj), tail_(obj), count_(1) {}
  115. explicit hazptr_obj_list(
  116. hazptr_obj<Atom>* head,
  117. hazptr_obj<Atom>* tail,
  118. int count) noexcept
  119. : head_(head), tail_(tail), count_(count) {}
  120. hazptr_obj<Atom>* head() {
  121. return head_;
  122. }
  123. hazptr_obj<Atom>* tail() {
  124. return tail_;
  125. }
  126. int count() {
  127. return count_;
  128. }
  129. void push(hazptr_obj<Atom>* obj) {
  130. obj->set_next(head_);
  131. head_ = obj;
  132. if (tail_ == nullptr) {
  133. tail_ = obj;
  134. }
  135. ++count_;
  136. }
  137. void splice(hazptr_obj_list<Atom>& l) {
  138. if (l.count() == 0) {
  139. return;
  140. }
  141. if (count() == 0) {
  142. head_ = l.head();
  143. } else {
  144. tail_->set_next(l.head());
  145. }
  146. tail_ = l.tail();
  147. count_ += l.count();
  148. l.clear();
  149. }
  150. void clear() {
  151. head_ = nullptr;
  152. tail_ = nullptr;
  153. count_ = 0;
  154. }
  155. }; // hazptr_obj_list
  156. /**
  157. * hazptr_deleter
  158. *
  159. * For empty base optimization.
  160. */
  161. template <typename T, typename D>
  162. class hazptr_deleter {
  163. D deleter_;
  164. public:
  165. void set_deleter(D d = {}) {
  166. deleter_ = std::move(d);
  167. }
  168. void delete_obj(T* p) {
  169. deleter_(p);
  170. }
  171. };
  172. template <typename T>
  173. class hazptr_deleter<T, std::default_delete<T>> {
  174. public:
  175. void set_deleter(std::default_delete<T> = {}) {}
  176. void delete_obj(T* p) {
  177. delete p;
  178. }
  179. };
  180. /**
  181. * hazptr_obj_base
  182. *
  183. * Base template for objects protected by hazard pointers.
  184. */
  185. template <typename T, template <typename> class Atom, typename D>
  186. class hazptr_obj_base : public hazptr_obj<Atom>, public hazptr_deleter<T, D> {
  187. public:
  188. /* Retire a removed object and pass the responsibility for
  189. * reclaiming it to the hazptr library */
  190. void retire(
  191. D deleter = {},
  192. hazptr_domain<Atom>& domain = default_hazptr_domain<Atom>()) {
  193. pre_retire(std::move(deleter));
  194. set_reclaim();
  195. this->push_to_retired(domain); // defined in hazptr_obj
  196. }
  197. void retire(hazptr_domain<Atom>& domain) {
  198. retire({}, domain);
  199. }
  200. private:
  201. void pre_retire(D deleter) {
  202. this->pre_retire_check(); // defined in hazptr_obj
  203. this->set_deleter(std::move(deleter));
  204. }
  205. void set_reclaim() {
  206. this->reclaim_ = [](hazptr_obj<Atom>* p, hazptr_obj_list<Atom>&) {
  207. auto hobp = static_cast<hazptr_obj_base<T, Atom, D>*>(p);
  208. auto obj = static_cast<T*>(hobp);
  209. hobp->delete_obj(obj);
  210. };
  211. }
  212. }; // hazptr_obj_base
  213. } // namespace folly