runnable_utils.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. // Original author: ekr@rtfm.com
  6. #ifndef runnable_utils_h__
  7. #define runnable_utils_h__
  8. #include "nsThreadUtils.h"
  9. #include "mozilla/IndexSequence.h"
  10. #include "mozilla/Move.h"
  11. #include "mozilla/RefPtr.h"
  12. #include "mozilla/Tuple.h"
  13. // Abstract base class for all of our templates
  14. namespace mozilla {
  15. namespace detail {
  16. enum RunnableResult {
  17. NoResult,
  18. ReturnsResult
  19. };
  20. static inline nsresult
  21. RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flags)
  22. {
  23. nsCOMPtr<nsIRunnable> runnable_ref(runnable);
  24. if (thread) {
  25. bool on;
  26. nsresult rv;
  27. rv = thread->IsOnCurrentThread(&on);
  28. // If the target thread has already shut down, we don't want to assert.
  29. if (rv != NS_ERROR_NOT_INITIALIZED) {
  30. MOZ_ASSERT(NS_SUCCEEDED(rv));
  31. }
  32. if (NS_WARN_IF(NS_FAILED(rv))) {
  33. // we're going to destroy the runnable on this thread!
  34. return rv;
  35. }
  36. if (!on) {
  37. return thread->Dispatch(runnable_ref.forget(), flags);
  38. }
  39. }
  40. return runnable_ref->Run();
  41. }
  42. template<RunnableResult result>
  43. class runnable_args_base : public Runnable {
  44. public:
  45. NS_IMETHOD Run() = 0;
  46. };
  47. template<typename R>
  48. struct RunnableFunctionCallHelper
  49. {
  50. template<typename FunType, typename... Args, size_t... Indices>
  51. static R apply(FunType func, Tuple<Args...>& args, IndexSequence<Indices...>)
  52. {
  53. return func(Get<Indices>(args)...);
  54. }
  55. };
  56. // A void specialization is needed in the case where the template instantiator
  57. // knows we don't want to return a value, but we don't know whether the called
  58. // function returns void or something else.
  59. template<>
  60. struct RunnableFunctionCallHelper<void>
  61. {
  62. template<typename FunType, typename... Args, size_t... Indices>
  63. static void apply(FunType func, Tuple<Args...>& args, IndexSequence<Indices...>)
  64. {
  65. func(Get<Indices>(args)...);
  66. }
  67. };
  68. template<typename R>
  69. struct RunnableMethodCallHelper
  70. {
  71. template<typename Class, typename M, typename... Args, size_t... Indices>
  72. static R apply(Class obj, M method, Tuple<Args...>& args, IndexSequence<Indices...>)
  73. {
  74. return ((*obj).*method)(Get<Indices>(args)...);
  75. }
  76. };
  77. // A void specialization is needed in the case where the template instantiator
  78. // knows we don't want to return a value, but we don't know whether the called
  79. // method returns void or something else.
  80. template<>
  81. struct RunnableMethodCallHelper<void>
  82. {
  83. template<typename Class, typename M, typename... Args, size_t... Indices>
  84. static void apply(Class obj, M method, Tuple<Args...>& args, IndexSequence<Indices...>)
  85. {
  86. ((*obj).*method)(Get<Indices>(args)...);
  87. }
  88. };
  89. }
  90. template<typename FunType, typename... Args>
  91. class runnable_args_func : public detail::runnable_args_base<detail::NoResult>
  92. {
  93. public:
  94. // |explicit| to pacify static analysis when there are no |args|.
  95. explicit runnable_args_func(FunType f, Args&&... args)
  96. : mFunc(f), mArgs(Forward<Args>(args)...)
  97. {}
  98. NS_IMETHOD Run() {
  99. detail::RunnableFunctionCallHelper<void>::apply(mFunc, mArgs, typename IndexSequenceFor<Args...>::Type());
  100. return NS_OK;
  101. }
  102. private:
  103. FunType mFunc;
  104. Tuple<Args...> mArgs;
  105. };
  106. template<typename FunType, typename... Args>
  107. runnable_args_func<FunType, Args...>*
  108. WrapRunnableNM(FunType f, Args... args)
  109. {
  110. return new runnable_args_func<FunType, Args...>(f, Move(args)...);
  111. }
  112. template<typename Ret, typename FunType, typename... Args>
  113. class runnable_args_func_ret : public detail::runnable_args_base<detail::ReturnsResult>
  114. {
  115. public:
  116. runnable_args_func_ret(Ret* ret, FunType f, Args&&... args)
  117. : mReturn(ret), mFunc(f), mArgs(Forward<Args>(args)...)
  118. {}
  119. NS_IMETHOD Run() {
  120. *mReturn = detail::RunnableFunctionCallHelper<Ret>::apply(mFunc, mArgs, typename IndexSequenceFor<Args...>::Type());
  121. return NS_OK;
  122. }
  123. private:
  124. Ret* mReturn;
  125. FunType mFunc;
  126. Tuple<Args...> mArgs;
  127. };
  128. template<typename R, typename FunType, typename... Args>
  129. runnable_args_func_ret<R, FunType, Args...>*
  130. WrapRunnableNMRet(R* ret, FunType f, Args... args)
  131. {
  132. return new runnable_args_func_ret<R, FunType, Args...>(ret, f, Move(args)...);
  133. }
  134. template<typename Class, typename M, typename... Args>
  135. class runnable_args_memfn : public detail::runnable_args_base<detail::NoResult>
  136. {
  137. public:
  138. runnable_args_memfn(Class obj, M method, Args&&... args)
  139. : mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
  140. {}
  141. NS_IMETHOD Run() {
  142. detail::RunnableMethodCallHelper<void>::apply(mObj, mMethod, mArgs, typename IndexSequenceFor<Args...>::Type());
  143. return NS_OK;
  144. }
  145. private:
  146. Class mObj;
  147. M mMethod;
  148. Tuple<Args...> mArgs;
  149. };
  150. template<typename Class, typename M, typename... Args>
  151. runnable_args_memfn<Class, M, Args...>*
  152. WrapRunnable(Class obj, M method, Args... args)
  153. {
  154. return new runnable_args_memfn<Class, M, Args...>(obj, method, Move(args)...);
  155. }
  156. template<typename Ret, typename Class, typename M, typename... Args>
  157. class runnable_args_memfn_ret : public detail::runnable_args_base<detail::ReturnsResult>
  158. {
  159. public:
  160. runnable_args_memfn_ret(Ret* ret, Class obj, M method, Args... args)
  161. : mReturn(ret), mObj(obj), mMethod(method), mArgs(Forward<Args>(args)...)
  162. {}
  163. NS_IMETHOD Run() {
  164. *mReturn = detail::RunnableMethodCallHelper<Ret>::apply(mObj, mMethod, mArgs, typename IndexSequenceFor<Args...>::Type());
  165. return NS_OK;
  166. }
  167. private:
  168. Ret* mReturn;
  169. Class mObj;
  170. M mMethod;
  171. Tuple<Args...> mArgs;
  172. };
  173. template<typename R, typename Class, typename M, typename... Args>
  174. runnable_args_memfn_ret<R, Class, M, Args...>*
  175. WrapRunnableRet(R* ret, Class obj, M method, Args... args)
  176. {
  177. return new runnable_args_memfn_ret<R, Class, M, Args...>(ret, obj, method, Move(args)...);
  178. }
  179. static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base<detail::NoResult> *runnable, uint32_t flags) {
  180. return detail::RunOnThreadInternal(thread, static_cast<nsIRunnable *>(runnable), flags);
  181. }
  182. static inline nsresult
  183. RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base<detail::ReturnsResult> *runnable)
  184. {
  185. return detail::RunOnThreadInternal(thread, static_cast<nsIRunnable *>(runnable), NS_DISPATCH_SYNC);
  186. }
  187. #ifdef DEBUG
  188. #define ASSERT_ON_THREAD(t) do { \
  189. if (t) { \
  190. bool on; \
  191. nsresult rv; \
  192. rv = t->IsOnCurrentThread(&on); \
  193. MOZ_ASSERT(NS_SUCCEEDED(rv)); \
  194. MOZ_ASSERT(on); \
  195. } \
  196. } while(0)
  197. #else
  198. #define ASSERT_ON_THREAD(t)
  199. #endif
  200. template <class T>
  201. class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
  202. public:
  203. explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
  204. NS_IMETHOD Run() {
  205. ref_ = nullptr;
  206. return NS_OK;
  207. }
  208. private:
  209. RefPtr<T> ref_;
  210. };
  211. template <typename T>
  212. DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref)
  213. {
  214. return new DispatchedRelease<T>(ref);
  215. }
  216. } /* namespace mozilla */
  217. #endif