Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : #ifndef BASE_TASK_H_
8 : #define BASE_TASK_H_
9 :
10 : #include "base/revocable_store.h"
11 : #include "base/tuple.h"
12 : #include "mozilla/IndexSequence.h"
13 : #include "mozilla/Tuple.h"
14 : #include "nsISupportsImpl.h"
15 : #include "nsThreadUtils.h"
16 :
17 : // Helper functions so that we can call a function a pass it arguments that come
18 : // from a Tuple.
19 :
20 : namespace details {
21 :
22 : // Call the given method on the given object. Arguments are passed by move
23 : // semantics from the given tuple. If the tuple has length N, the sequence must
24 : // be IndexSequence<0, 1, ..., N-1>.
25 : template<size_t... Indices, class ObjT, class Method, typename... Args>
26 0 : void CallMethod(mozilla::IndexSequence<Indices...>, ObjT* obj, Method method,
27 : mozilla::Tuple<Args...>& arg)
28 : {
29 0 : (obj->*method)(mozilla::Move(mozilla::Get<Indices>(arg))...);
30 0 : }
31 :
32 : // Same as above, but call a function.
33 : template<size_t... Indices, typename Function, typename... Args>
34 7 : void CallFunction(mozilla::IndexSequence<Indices...>, Function function,
35 : mozilla::Tuple<Args...>& arg)
36 : {
37 7 : (*function)(mozilla::Move(mozilla::Get<Indices>(arg))...);
38 7 : }
39 :
40 : } // namespace details
41 :
42 : // Call a method on the given object. Arguments are passed by move semantics
43 : // from the given tuple.
44 : template<class ObjT, class Method, typename... Args>
45 0 : void DispatchTupleToMethod(ObjT* obj, Method method, mozilla::Tuple<Args...>& arg)
46 : {
47 0 : details::CallMethod(typename mozilla::IndexSequenceFor<Args...>::Type(),
48 : obj, method, arg);
49 0 : }
50 :
51 : // Same as above, but call a function.
52 : template<typename Function, typename... Args>
53 7 : void DispatchTupleToFunction(Function function, mozilla::Tuple<Args...>& arg)
54 : {
55 7 : details::CallFunction(typename mozilla::IndexSequenceFor<Args...>::Type(),
56 : function, arg);
57 7 : }
58 :
59 : // Scoped Factories ------------------------------------------------------------
60 : //
61 : // These scoped factory objects can be used by non-refcounted objects to safely
62 : // place tasks in a message loop. Each factory guarantees that the tasks it
63 : // produces will not run after the factory is destroyed. Commonly, factories
64 : // are declared as class members, so the class' tasks will automatically cancel
65 : // when the class instance is destroyed.
66 : //
67 : // Exampe Usage:
68 : //
69 : // class MyClass {
70 : // private:
71 : // // This factory will be used to schedule invocations of SomeMethod.
72 : // ScopedRunnableMethodFactory<MyClass> some_method_factory_;
73 : //
74 : // public:
75 : // // It is safe to suppress warning 4355 here.
76 : // MyClass() : some_method_factory_(this) { }
77 : //
78 : // void SomeMethod() {
79 : // // If this function might be called directly, you might want to revoke
80 : // // any outstanding runnable methods scheduled to call it. If it's not
81 : // // referenced other than by the factory, this is unnecessary.
82 : // some_method_factory_.RevokeAll();
83 : // ...
84 : // }
85 : //
86 : // void ScheduleSomeMethod() {
87 : // // If you'd like to only only have one pending task at a time, test for
88 : // // |empty| before manufacturing another task.
89 : // if (!some_method_factory_.empty())
90 : // return;
91 : //
92 : // // The factories are not thread safe, so always invoke on
93 : // // |MessageLoop::current()|.
94 : // MessageLoop::current()->PostDelayedTask(
95 : // some_method_factory_.NewRunnableMethod(&MyClass::SomeMethod),
96 : // kSomeMethodDelayMS);
97 : // }
98 : // };
99 :
100 : // A ScopedTaskFactory produces tasks of type |TaskType| and prevents them from
101 : // running after it is destroyed.
102 : template<class TaskType>
103 : class ScopedTaskFactory : public RevocableStore {
104 : public:
105 : ScopedTaskFactory() { }
106 :
107 : // Create a new task.
108 : inline TaskType* NewTask() {
109 : return new TaskWrapper(this);
110 : }
111 :
112 : class TaskWrapper : public TaskType {
113 : public:
114 0 : explicit TaskWrapper(RevocableStore* store) : revocable_(store) { }
115 :
116 0 : NS_IMETHOD Run() override {
117 0 : if (!revocable_.revoked())
118 0 : TaskType::Run();
119 0 : return NS_OK;
120 : }
121 :
122 0 : ~TaskWrapper() {
123 0 : NS_ASSERT_OWNINGTHREAD(TaskWrapper);
124 0 : }
125 :
126 : private:
127 : Revocable revocable_;
128 :
129 : NS_DECL_OWNINGTHREAD
130 :
131 : DISALLOW_EVIL_CONSTRUCTORS(TaskWrapper);
132 : };
133 :
134 : private:
135 : DISALLOW_EVIL_CONSTRUCTORS(ScopedTaskFactory);
136 : };
137 :
138 : // A ScopedRunnableMethodFactory creates runnable methods for a specified
139 : // object. This is particularly useful for generating callbacks for
140 : // non-reference counted objects when the factory is a member of the object.
141 : template<class T>
142 13 : class ScopedRunnableMethodFactory : public RevocableStore {
143 : public:
144 41 : explicit ScopedRunnableMethodFactory(T* object) : object_(object) { }
145 :
146 : template <class Method, typename... Elements>
147 : inline already_AddRefed<mozilla::Runnable>
148 0 : NewRunnableMethod(Method method, Elements&&... elements) {
149 : typedef mozilla::Tuple<typename mozilla::Decay<Elements>::Type...> ArgsTuple;
150 : typedef RunnableMethod<Method, ArgsTuple> Runnable;
151 : typedef typename ScopedTaskFactory<Runnable>::TaskWrapper TaskWrapper;
152 :
153 0 : RefPtr<TaskWrapper> task = new TaskWrapper(this);
154 0 : task->Init(object_, method, mozilla::MakeTuple(mozilla::Forward<Elements>(elements)...));
155 0 : return task.forget();
156 : }
157 :
158 : protected:
159 : template <class Method, class Params>
160 0 : class RunnableMethod : public mozilla::Runnable {
161 : public:
162 0 : RunnableMethod()
163 0 : : mozilla::Runnable("ScopedRunnableMethodFactory::RunnableMethod")
164 : {
165 0 : }
166 :
167 0 : void Init(T* obj, Method meth, Params&& params)
168 : {
169 0 : obj_ = obj;
170 0 : meth_ = meth;
171 0 : params_ = mozilla::Forward<Params>(params);
172 0 : }
173 :
174 0 : NS_IMETHOD Run() override {
175 0 : DispatchTupleToMethod(obj_, meth_, params_);
176 0 : return NS_OK;
177 : }
178 :
179 : private:
180 : T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by "
181 : "external factors.") obj_;
182 : Method meth_;
183 : Params params_;
184 :
185 : DISALLOW_EVIL_CONSTRUCTORS(RunnableMethod);
186 : };
187 :
188 : private:
189 : T* object_;
190 :
191 : DISALLOW_EVIL_CONSTRUCTORS(ScopedRunnableMethodFactory);
192 : };
193 :
194 : // General task implementations ------------------------------------------------
195 :
196 : // Task to delete an object
197 : template<class T>
198 0 : class DeleteTask : public mozilla::CancelableRunnable {
199 : public:
200 0 : explicit DeleteTask(T* obj)
201 : : mozilla::CancelableRunnable("DeleteTask")
202 0 : , obj_(obj)
203 : {
204 0 : }
205 0 : NS_IMETHOD Run() override {
206 0 : delete obj_;
207 0 : return NS_OK;
208 : }
209 0 : virtual nsresult Cancel() override {
210 0 : obj_ = NULL;
211 0 : return NS_OK;
212 : }
213 : private:
214 : T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by "
215 : "external factors.") obj_;
216 : };
217 :
218 : // RunnableMethodTraits --------------------------------------------------------
219 : //
220 : // This traits-class is used by RunnableMethod to manage the lifetime of the
221 : // callee object. By default, it is assumed that the callee supports AddRef
222 : // and Release methods. A particular class can specialize this template to
223 : // define other lifetime management. For example, if the callee is known to
224 : // live longer than the RunnableMethod object, then a RunnableMethodTraits
225 : // struct could be defined with empty RetainCallee and ReleaseCallee methods.
226 :
227 : template <class T>
228 0 : struct RunnableMethodTraits {
229 0 : static void RetainCallee(T* obj) {
230 0 : obj->AddRef();
231 0 : }
232 0 : static void ReleaseCallee(T* obj) {
233 0 : obj->Release();
234 0 : }
235 : };
236 :
237 : // This allows using the NewRunnableMethod() functions with a const pointer
238 : // to the callee object. See the similar support in nsRefPtr for a rationale
239 : // of why this is reasonable.
240 : template <class T>
241 : struct RunnableMethodTraits<const T> {
242 : static void RetainCallee(const T* obj) {
243 : const_cast<T*>(obj)->AddRef();
244 : }
245 : static void ReleaseCallee(const T* obj) {
246 : const_cast<T*>(obj)->Release();
247 : }
248 : };
249 :
250 : // RunnableMethod and RunnableFunction -----------------------------------------
251 : //
252 : // Runnable methods are a type of task that call a function on an object when
253 : // they are run. We implement both an object and a set of NewRunnableMethod and
254 : // NewRunnableFunction functions for convenience. These functions are
255 : // overloaded and will infer the template types, simplifying calling code.
256 : //
257 : // The template definitions all use the following names:
258 : // T - the class type of the object you're supplying
259 : // this is not needed for the Static version of the call
260 : // Method/Function - the signature of a pointer to the method or function you
261 : // want to call
262 : // Param - the parameter(s) to the method, possibly packed as a Tuple
263 : // A - the first parameter (if any) to the method
264 : // B - the second parameter (if any) to the mathod
265 : //
266 : // Put these all together and you get an object that can call a method whose
267 : // signature is:
268 : // R T::MyFunction([A[, B]])
269 : //
270 : // Usage:
271 : // PostTask(NewRunnableMethod(object, &Object::method[, a[, b]])
272 : // PostTask(NewRunnableFunction(&function[, a[, b]])
273 :
274 : // RunnableMethod and NewRunnableMethod implementation -------------------------
275 :
276 : template <class T, class Method, class Params>
277 : class RunnableMethod : public mozilla::CancelableRunnable,
278 : public RunnableMethodTraits<T> {
279 : public:
280 0 : RunnableMethod(T* obj, Method meth, Params&& params)
281 : : mozilla::CancelableRunnable("RunnableMethod")
282 : , obj_(obj)
283 : , meth_(meth)
284 0 : , params_(mozilla::Forward<Params>(params))
285 : {
286 0 : this->RetainCallee(obj_);
287 0 : }
288 0 : ~RunnableMethod() {
289 0 : ReleaseCallee();
290 0 : }
291 :
292 0 : NS_IMETHOD Run() override {
293 0 : if (obj_)
294 0 : DispatchTupleToMethod(obj_, meth_, params_);
295 0 : return NS_OK;
296 : }
297 :
298 0 : virtual nsresult Cancel() override {
299 0 : ReleaseCallee();
300 0 : return NS_OK;
301 : }
302 :
303 : private:
304 0 : void ReleaseCallee() {
305 0 : if (obj_) {
306 0 : RunnableMethodTraits<T>::ReleaseCallee(obj_);
307 0 : obj_ = nullptr;
308 : }
309 0 : }
310 :
311 : // This is owning because of the RetainCallee and ReleaseCallee calls in the
312 : // constructor and destructor.
313 : T* MOZ_OWNING_REF obj_;
314 : Method meth_;
315 : Params params_;
316 : };
317 :
318 : namespace dont_add_new_uses_of_this {
319 :
320 : // Don't add new uses of this!!!!
321 : template <class T, class Method, typename... Args>
322 : inline already_AddRefed<mozilla::Runnable>
323 0 : NewRunnableMethod(T* object, Method method, Args&&... args) {
324 : typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple;
325 : RefPtr<mozilla::Runnable> t =
326 0 : new RunnableMethod<T, Method, ArgsTuple>(object, method,
327 0 : mozilla::MakeTuple(mozilla::Forward<Args>(args)...));
328 0 : return t.forget();
329 : }
330 :
331 : } // namespace dont_add_new_uses_of_this
332 :
333 : // RunnableFunction and NewRunnableFunction implementation ---------------------
334 :
335 : template <class Function, class Params>
336 : class RunnableFunction : public mozilla::CancelableRunnable {
337 : public:
338 7 : RunnableFunction(Function function, Params&& params)
339 : : mozilla::CancelableRunnable("RunnableFunction")
340 : , function_(function)
341 7 : , params_(mozilla::Forward<Params>(params))
342 : {
343 7 : }
344 :
345 14 : ~RunnableFunction() {
346 21 : }
347 :
348 7 : NS_IMETHOD Run() override {
349 7 : if (function_)
350 7 : DispatchTupleToFunction(function_, params_);
351 7 : return NS_OK;
352 : }
353 :
354 0 : virtual nsresult Cancel() override {
355 0 : function_ = nullptr;
356 0 : return NS_OK;
357 : }
358 :
359 : Function function_;
360 : Params params_;
361 : };
362 :
363 : template <class Function, typename... Args>
364 : inline already_AddRefed<mozilla::CancelableRunnable>
365 1 : NewCancelableRunnableFunction(Function function, Args&&... args) {
366 : typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple;
367 : RefPtr<mozilla::CancelableRunnable> t =
368 1 : new RunnableFunction<Function, ArgsTuple>(function,
369 3 : mozilla::MakeTuple(mozilla::Forward<Args>(args)...));
370 2 : return t.forget();
371 : }
372 :
373 : template <class Function, typename... Args>
374 : inline already_AddRefed<mozilla::Runnable>
375 6 : NewRunnableFunction(Function function, Args&&... args) {
376 : typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple;
377 : RefPtr<mozilla::Runnable> t =
378 6 : new RunnableFunction<Function, ArgsTuple>(function,
379 18 : mozilla::MakeTuple(mozilla::Forward<Args>(args)...));
380 12 : return t.forget();
381 : }
382 :
383 : #endif // BASE_TASK_H_
|