Executor.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright 2014-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 <cassert>
  18. #include <climits>
  19. #include <folly/Function.h>
  20. #include <folly/Utility.h>
  21. namespace folly {
  22. using Func = Function<void()>;
  23. /// An Executor accepts units of work with add(), which should be
  24. /// threadsafe.
  25. class Executor {
  26. public:
  27. // Workaround for a linkage problem with explicitly defaulted dtor t22914621
  28. virtual ~Executor() {}
  29. /// Enqueue a function to executed by this executor. This and all
  30. /// variants must be threadsafe.
  31. virtual void add(Func) = 0;
  32. /// Enqueue a function with a given priority, where 0 is the medium priority
  33. /// This is up to the implementation to enforce
  34. virtual void addWithPriority(Func, int8_t priority);
  35. virtual uint8_t getNumPriorities() const {
  36. return 1;
  37. }
  38. static const int8_t LO_PRI = SCHAR_MIN;
  39. static const int8_t MID_PRI = 0;
  40. static const int8_t HI_PRI = SCHAR_MAX;
  41. template <typename ExecutorT = Executor>
  42. class KeepAlive {
  43. public:
  44. KeepAlive() = default;
  45. ~KeepAlive() {
  46. reset();
  47. }
  48. KeepAlive(KeepAlive&& other) noexcept
  49. : executorAndDummyFlag_(exchange(other.executorAndDummyFlag_, 0)) {}
  50. template <
  51. typename OtherExecutor,
  52. typename = typename std::enable_if<
  53. std::is_convertible<OtherExecutor*, ExecutorT*>::value>::type>
  54. /* implicit */ KeepAlive(KeepAlive<OtherExecutor>&& other) noexcept
  55. : KeepAlive(other.get(), other.executorAndDummyFlag_ & kDummyFlag) {
  56. other.executorAndDummyFlag_ = 0;
  57. }
  58. KeepAlive& operator=(KeepAlive&& other) {
  59. reset();
  60. executorAndDummyFlag_ = exchange(other.executorAndDummyFlag_, 0);
  61. return *this;
  62. }
  63. template <
  64. typename OtherExecutor,
  65. typename = typename std::enable_if<
  66. std::is_convertible<OtherExecutor*, ExecutorT*>::value>::type>
  67. KeepAlive& operator=(KeepAlive<OtherExecutor>&& other) {
  68. return *this = KeepAlive(std::move(other));
  69. }
  70. void reset() {
  71. if (Executor* executor = get()) {
  72. if (exchange(executorAndDummyFlag_, 0) & kDummyFlag) {
  73. return;
  74. }
  75. executor->keepAliveRelease();
  76. }
  77. }
  78. explicit operator bool() const {
  79. return executorAndDummyFlag_;
  80. }
  81. ExecutorT* get() const {
  82. return reinterpret_cast<ExecutorT*>(
  83. executorAndDummyFlag_ & kExecutorMask);
  84. }
  85. ExecutorT& operator*() const {
  86. return *get();
  87. }
  88. ExecutorT* operator->() const {
  89. return get();
  90. }
  91. KeepAlive copy() const {
  92. return getKeepAliveToken(get());
  93. }
  94. private:
  95. static constexpr intptr_t kDummyFlag = 1;
  96. static constexpr intptr_t kExecutorMask = ~kDummyFlag;
  97. friend class Executor;
  98. template <typename OtherExecutor>
  99. friend class KeepAlive;
  100. KeepAlive(ExecutorT* executor, bool dummy)
  101. : executorAndDummyFlag_(
  102. reinterpret_cast<intptr_t>(executor) | (dummy ? kDummyFlag : 0)) {
  103. assert(executor);
  104. assert(
  105. (reinterpret_cast<intptr_t>(executor) & kExecutorMask) ==
  106. reinterpret_cast<intptr_t>(executor));
  107. }
  108. intptr_t executorAndDummyFlag_{reinterpret_cast<intptr_t>(nullptr)};
  109. };
  110. template <typename ExecutorT>
  111. static KeepAlive<ExecutorT> getKeepAliveToken(ExecutorT* executor) {
  112. static_assert(
  113. std::is_base_of<Executor, ExecutorT>::value,
  114. "getKeepAliveToken only works for folly::Executor implementations.");
  115. if (!executor) {
  116. return {};
  117. }
  118. folly::Executor* executorPtr = executor;
  119. if (executorPtr->keepAliveAcquire()) {
  120. return makeKeepAlive<ExecutorT>(executor);
  121. }
  122. return makeKeepAliveDummy<ExecutorT>(executor);
  123. }
  124. template <typename ExecutorT>
  125. static KeepAlive<ExecutorT> getKeepAliveToken(ExecutorT& executor) {
  126. static_assert(
  127. std::is_base_of<Executor, ExecutorT>::value,
  128. "getKeepAliveToken only works for folly::Executor implementations.");
  129. return getKeepAliveToken(&executor);
  130. }
  131. protected:
  132. /**
  133. * Returns true if the KeepAlive is constructed from an executor that does
  134. * not support the keep alive ref-counting functionality
  135. */
  136. template <typename ExecutorT>
  137. static bool isKeepAliveDummy(const KeepAlive<ExecutorT>& keepAlive) {
  138. return reinterpret_cast<intptr_t>(keepAlive.executorAndDummyFlag_) &
  139. KeepAlive<ExecutorT>::kDummyFlag;
  140. }
  141. // Acquire a keep alive token. Should return false if keep-alive mechanism
  142. // is not supported.
  143. virtual bool keepAliveAcquire();
  144. // Release a keep alive token previously acquired by keepAliveAcquire().
  145. // Will never be called if keepAliveAcquire() returns false.
  146. virtual void keepAliveRelease();
  147. template <typename ExecutorT>
  148. static KeepAlive<ExecutorT> makeKeepAlive(ExecutorT* executor) {
  149. static_assert(
  150. std::is_base_of<Executor, ExecutorT>::value,
  151. "makeKeepAlive only works for folly::Executor implementations.");
  152. return KeepAlive<ExecutorT>{executor, false};
  153. }
  154. private:
  155. template <typename ExecutorT>
  156. static KeepAlive<ExecutorT> makeKeepAliveDummy(ExecutorT* executor) {
  157. static_assert(
  158. std::is_base_of<Executor, ExecutorT>::value,
  159. "makeKeepAliveDummy only works for folly::Executor implementations.");
  160. return KeepAlive<ExecutorT>{executor, true};
  161. }
  162. };
  163. /// Returns a keep-alive token which guarantees that Executor will keep
  164. /// processing tasks until the token is released (if supported by Executor).
  165. /// KeepAlive always contains a valid pointer to an Executor.
  166. template <typename ExecutorT>
  167. Executor::KeepAlive<ExecutorT> getKeepAliveToken(ExecutorT* executor) {
  168. static_assert(
  169. std::is_base_of<Executor, ExecutorT>::value,
  170. "getKeepAliveToken only works for folly::Executor implementations.");
  171. return Executor::getKeepAliveToken(executor);
  172. }
  173. template <typename ExecutorT>
  174. Executor::KeepAlive<ExecutorT> getKeepAliveToken(ExecutorT& executor) {
  175. static_assert(
  176. std::is_base_of<Executor, ExecutorT>::value,
  177. "getKeepAliveToken only works for folly::Executor implementations.");
  178. return getKeepAliveToken(&executor);
  179. }
  180. } // namespace folly