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 <utility>
13 
14 #include "mozilla/RefPtr.h"
15 #include "nsThreadUtils.h"
16 #include <functional>
17 #include <tuple>
18 #include <type_traits>
19 
20 // Abstract base class for all of our templates
21 namespace mozilla {
22 
23 namespace detail {
24 
25 enum RunnableResult { NoResult, ReturnsResult };
26 
RunOnThreadInternal(nsIEventTarget * thread,nsIRunnable * runnable,uint32_t flags)27 static inline nsresult RunOnThreadInternal(nsIEventTarget* thread,
28                                            nsIRunnable* runnable,
29                                            uint32_t flags) {
30   return thread->Dispatch(runnable, flags);
31 }
32 
33 template <RunnableResult result>
34 class runnable_args_base : public Runnable {
35  public:
runnable_args_base()36   runnable_args_base() : Runnable("media-runnable_args_base") {}
37 
Run()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>
runnable_args_func(FunType f,Arguments &&...args)63   explicit runnable_args_func(FunType f, Arguments&&... args)
64       : mFunc(f), mArgs(std::forward<Arguments>(args)...) {}
65 
66  protected:
RunInternal()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>
WrapRunnableNM(FunType f,Args &&...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>
runnable_args_func_ret(Ret * ret,FunType f,Arguments &&...args)88   runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args)
89       : mReturn(ret), mFunc(f), mArgs(std::forward<Arguments>(args)...) {}
90 
91  protected:
RunInternal()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>
WrapRunnableNMRet(R * ret,FunType f,Args &&...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>
runnable_args_memfn(Class && obj,M method,Arguments &&...args)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:
RunInternal()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>
WrapRunnable(Class && obj,M method,Args &&...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>
runnable_args_memfn_ret(Ret * ret,Class && obj,M method,Arguments...args)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:
RunInternal()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>
WrapRunnableRet(R * ret,Class && obj,M method,Args &&...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 
RUN_ON_THREAD(nsIEventTarget * thread,detail::runnable_args_base<detail::NoResult> * runnable,uint32_t flags)173 static inline nsresult RUN_ON_THREAD(
174     nsIEventTarget* thread,
175     detail::runnable_args_base<detail::NoResult>* runnable, uint32_t flags) {
176   return detail::RunOnThreadInternal(
177       thread, static_cast<nsIRunnable*>(runnable), flags);
178 }
179 
RUN_ON_THREAD(nsIEventTarget * thread,detail::runnable_args_base<detail::ReturnsResult> * runnable)180 static inline nsresult RUN_ON_THREAD(
181     nsIEventTarget* thread,
182     detail::runnable_args_base<detail::ReturnsResult>* runnable) {
183   return detail::RunOnThreadInternal(
184       thread, static_cast<nsIRunnable*>(runnable), NS_DISPATCH_SYNC);
185 }
186 
187 #ifdef DEBUG
188 #  define ASSERT_ON_THREAD(t)           \
189     do {                                \
190       if (t) {                          \
191         bool on;                        \
192         nsresult rv;                    \
193         rv = t->IsOnCurrentThread(&on); \
194         MOZ_ASSERT(NS_SUCCEEDED(rv));   \
195         MOZ_ASSERT(on);                 \
196       }                                 \
197     } while (0)
198 #else
199 #  define ASSERT_ON_THREAD(t)
200 #endif
201 
202 template <class T>
203 class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
204  public:
DispatchedRelease(already_AddRefed<T> & ref)205   explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
206 
207  protected:
RunInternal()208   void RunInternal() override { ref_ = nullptr; }
209 
210  private:
211   RefPtr<T> ref_;
212 };
213 
214 template <typename T>
WrapRelease(already_AddRefed<T> && ref)215 DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref) {
216   return new DispatchedRelease<T>(ref);
217 }
218 
219 } /* namespace mozilla */
220 
221 #endif
222