runnable_utils.h (6565B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // Original author: ekr@rtfm.com 8 9 #ifndef runnable_utils_h__ 10 #define runnable_utils_h__ 11 12 #include <functional> 13 #include <tuple> 14 #include <type_traits> 15 #include <utility> 16 17 #include "mozilla/RefPtr.h" 18 #include "nsThreadUtils.h" 19 20 // Abstract base class for all of our templates 21 namespace mozilla { 22 23 namespace detail { 24 25 enum RunnableResult { NoResult, ReturnsResult }; 26 27 static inline nsresult RunOnThreadInternal( 28 nsIEventTarget* thread, nsIRunnable* runnable, 29 nsIEventTarget::DispatchFlags flags) { 30 return thread->Dispatch(runnable, flags); 31 } 32 33 template <RunnableResult result> 34 class runnable_args_base : public Runnable { 35 public: 36 runnable_args_base() : Runnable("media-runnable_args_base") {} 37 38 NS_IMETHOD Run() final { 39 MOZ_ASSERT(!mHasRun, "Can only be run once"); 40 41 RunInternal(); 42 #ifdef DEBUG 43 mHasRun = true; 44 #endif 45 46 return NS_OK; 47 } 48 49 protected: 50 virtual void RunInternal() = 0; 51 #ifdef DEBUG 52 bool mHasRun = false; 53 #endif 54 }; 55 56 } // namespace detail 57 58 template <typename FunType, typename... Args> 59 class runnable_args_func : public detail::runnable_args_base<detail::NoResult> { 60 public: 61 // |explicit| to pacify static analysis when there are no |args|. 62 template <typename... Arguments> 63 explicit runnable_args_func(FunType f, Arguments&&... args) 64 : mFunc(f), mArgs(std::forward<Arguments>(args)...) {} 65 66 protected: 67 void RunInternal() override { 68 std::apply(std::move(mFunc), std::move(mArgs)); 69 } 70 71 private: 72 FunType mFunc; 73 std::tuple<Args...> mArgs; 74 }; 75 76 template <typename FunType, typename... Args> 77 runnable_args_func<FunType, std::decay_t<Args>...>* WrapRunnableNM( 78 FunType f, Args&&... args) { 79 return new runnable_args_func<FunType, std::decay_t<Args>...>( 80 f, std::forward<Args>(args)...); 81 } 82 83 template <typename Ret, typename FunType, typename... Args> 84 class runnable_args_func_ret 85 : public detail::runnable_args_base<detail::ReturnsResult> { 86 public: 87 template <typename... Arguments> 88 runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args) 89 : mReturn(ret), mFunc(f), mArgs(std::forward<Arguments>(args)...) {} 90 91 protected: 92 void RunInternal() override { 93 *mReturn = std::apply(std::move(mFunc), std::move(mArgs)); 94 } 95 96 private: 97 Ret* mReturn; 98 FunType mFunc; 99 std::tuple<Args...> mArgs; 100 }; 101 102 template <typename R, typename FunType, typename... Args> 103 runnable_args_func_ret<R, FunType, std::decay_t<Args>...>* WrapRunnableNMRet( 104 R* ret, FunType f, Args&&... args) { 105 return new runnable_args_func_ret<R, FunType, std::decay_t<Args>...>( 106 ret, f, std::forward<Args>(args)...); 107 } 108 109 template <typename Class, typename M, typename... Args> 110 class runnable_args_memfn 111 : public detail::runnable_args_base<detail::NoResult> { 112 public: 113 template <typename... Arguments> 114 runnable_args_memfn(Class&& obj, M method, Arguments&&... args) 115 : mObj(std::forward<Class>(obj)), 116 mMethod(method), 117 mArgs(std::forward<Arguments>(args)...) {} 118 119 protected: 120 void RunInternal() override { 121 std::apply(std::mem_fn(mMethod), 122 std::tuple_cat(std::tie(mObj), std::move(mArgs))); 123 } 124 125 private: 126 // For holders such as RefPtr and UniquePtr make sure concrete copy is held 127 // rather than a potential dangling reference. 128 std::decay_t<Class> mObj; 129 M mMethod; 130 std::tuple<Args...> mArgs; 131 }; 132 133 template <typename Class, typename M, typename... Args> 134 runnable_args_memfn<Class, M, std::decay_t<Args>...>* WrapRunnable( 135 Class&& obj, M method, Args&&... args) { 136 return new runnable_args_memfn<Class, M, std::decay_t<Args>...>( 137 std::forward<Class>(obj), method, std::forward<Args>(args)...); 138 } 139 140 template <typename Ret, typename Class, typename M, typename... Args> 141 class runnable_args_memfn_ret 142 : public detail::runnable_args_base<detail::ReturnsResult> { 143 public: 144 template <typename... Arguments> 145 runnable_args_memfn_ret(Ret* ret, Class&& obj, M method, Arguments... args) 146 : mReturn(ret), 147 mObj(std::forward<Class>(obj)), 148 mMethod(method), 149 mArgs(std::forward<Arguments>(args)...) {} 150 151 protected: 152 void RunInternal() override { 153 *mReturn = std::apply(std::mem_fn(mMethod), 154 std::tuple_cat(std::tie(mObj), std::move(mArgs))); 155 } 156 157 private: 158 Ret* mReturn; 159 // For holders such as RefPtr and UniquePtr make sure concrete copy is held 160 // rather than a potential dangling reference. 161 std::decay_t<Class> mObj; 162 M mMethod; 163 std::tuple<Args...> mArgs; 164 }; 165 166 template <typename R, typename Class, typename M, typename... Args> 167 runnable_args_memfn_ret<R, Class, M, std::decay_t<Args>...>* WrapRunnableRet( 168 R* ret, Class&& obj, M method, Args&&... args) { 169 return new runnable_args_memfn_ret<R, Class, M, std::decay_t<Args>...>( 170 ret, std::forward<Class>(obj), method, std::forward<Args>(args)...); 171 } 172 173 static inline nsresult RUN_ON_THREAD( 174 nsIEventTarget* thread, 175 detail::runnable_args_base<detail::NoResult>* runnable, 176 nsIEventTarget::DispatchFlags flags) { 177 return detail::RunOnThreadInternal( 178 thread, static_cast<nsIRunnable*>(runnable), flags); 179 } 180 181 static inline nsresult RUN_ON_THREAD( 182 nsIEventTarget* thread, 183 detail::runnable_args_base<detail::ReturnsResult>* runnable) { 184 return NS_DispatchAndSpinEventLoopUntilComplete( 185 "webrtc RUN_ON_THREAD"_ns, thread, 186 do_AddRef(static_cast<nsIRunnable*>(runnable))); 187 } 188 189 #ifdef DEBUG 190 # define ASSERT_ON_THREAD(t) \ 191 do { \ 192 if (t) { \ 193 bool on; \ 194 nsresult rv; \ 195 rv = t->IsOnCurrentThread(&on); \ 196 MOZ_ASSERT(NS_SUCCEEDED(rv)); \ 197 MOZ_ASSERT(on); \ 198 } \ 199 } while (0) 200 #else 201 # define ASSERT_ON_THREAD(t) 202 #endif 203 204 template <class T> 205 class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> { 206 public: 207 explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {} 208 209 protected: 210 void RunInternal() override { ref_ = nullptr; } 211 212 private: 213 RefPtr<T> ref_; 214 }; 215 216 template <typename T> 217 DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref) { 218 return new DispatchedRelease<T>(ref); 219 } 220 221 } /* namespace mozilla */ 222 223 #endif