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