task.h (7948B)
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 13 #include "nsISupportsImpl.h" 14 #include "nsThreadUtils.h" 15 16 #include <type_traits> 17 #include <utility> 18 19 // Helper functions so that we can call a function a pass it arguments that come 20 // from a Tuple. 21 22 namespace details { 23 24 // Call the given method on the given object. Arguments are passed by move 25 // semantics from the given tuple. If the tuple has length N, the sequence must 26 // be IndexSequence<0, 1, ..., N-1>. 27 template <size_t... Indices, class ObjT, class Method, typename... Args> 28 void CallMethod(std::index_sequence<Indices...>, ObjT* obj, Method method, 29 std::tuple<Args...>& arg) { 30 (obj->*method)(std::move(std::get<Indices>(arg))...); 31 } 32 33 // Same as above, but call a function. 34 template <size_t... Indices, typename Function, typename... Args> 35 void CallFunction(std::index_sequence<Indices...>, Function function, 36 std::tuple<Args...>& arg) { 37 (*function)(std::move(std::get<Indices>(arg))...); 38 } 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 void DispatchTupleToMethod(ObjT* obj, Method method, std::tuple<Args...>& arg) { 46 details::CallMethod(std::index_sequence_for<Args...>{}, obj, method, arg); 47 } 48 49 // Same as above, but call a function. 50 template <typename Function, typename... Args> 51 void DispatchTupleToFunction(Function function, std::tuple<Args...>& arg) { 52 details::CallFunction(std::index_sequence_for<Args...>{}, function, arg); 53 } 54 55 // General task implementations ------------------------------------------------ 56 57 // Task to delete an object 58 template <class T> 59 class DeleteTask : public mozilla::CancelableRunnable { 60 public: 61 explicit DeleteTask(T* obj) 62 : mozilla::CancelableRunnable("DeleteTask"), obj_(obj) {} 63 NS_IMETHOD Run() override { 64 delete obj_; 65 return NS_OK; 66 } 67 virtual nsresult Cancel() override { 68 obj_ = NULL; 69 return NS_OK; 70 } 71 72 private: 73 T* MOZ_UNSAFE_REF( 74 "The validity of this pointer must be enforced by " 75 "external factors.") obj_; 76 }; 77 78 // RunnableMethodTraits -------------------------------------------------------- 79 // 80 // This traits-class is used by RunnableMethod to manage the lifetime of the 81 // callee object. By default, it is assumed that the callee supports AddRef 82 // and Release methods. A particular class can specialize this template to 83 // define other lifetime management. For example, if the callee is known to 84 // live longer than the RunnableMethod object, then a RunnableMethodTraits 85 // struct could be defined with empty RetainCallee and ReleaseCallee methods. 86 87 template <class T> 88 struct RunnableMethodTraits { 89 static void RetainCallee(T* obj) { obj->AddRef(); } 90 static void ReleaseCallee(T* obj) { obj->Release(); } 91 }; 92 93 // This allows using the NewRunnableMethod() functions with a const pointer 94 // to the callee object. See the similar support in nsRefPtr for a rationale 95 // of why this is reasonable. 96 template <class T> 97 struct RunnableMethodTraits<const T> { 98 static void RetainCallee(const T* obj) { const_cast<T*>(obj)->AddRef(); } 99 static void ReleaseCallee(const T* obj) { const_cast<T*>(obj)->Release(); } 100 }; 101 102 // RunnableMethod and RunnableFunction ----------------------------------------- 103 // 104 // Runnable methods are a type of task that call a function on an object when 105 // they are run. We implement both an object and a set of NewRunnableMethod and 106 // NewRunnableFunction functions for convenience. These functions are 107 // overloaded and will infer the template types, simplifying calling code. 108 // 109 // The template definitions all use the following names: 110 // T - the class type of the object you're supplying 111 // this is not needed for the Static version of the call 112 // Method/Function - the signature of a pointer to the method or function you 113 // want to call 114 // Param - the parameter(s) to the method, possibly packed as a Tuple 115 // A - the first parameter (if any) to the method 116 // B - the second parameter (if any) to the mathod 117 // 118 // Put these all together and you get an object that can call a method whose 119 // signature is: 120 // R T::MyFunction([A[, B]]) 121 // 122 // Usage: 123 // PostTask(NewRunnableMethod(object, &Object::method[, a[, b]]) 124 // PostTask(NewRunnableFunction(&function[, a[, b]]) 125 126 // RunnableMethod and NewRunnableMethod implementation ------------------------- 127 128 template <class T, class Method, class Params> 129 class RunnableMethod : public mozilla::CancelableRunnable, 130 public RunnableMethodTraits<T> { 131 public: 132 RunnableMethod(T* obj, Method meth, Params&& params) 133 : mozilla::CancelableRunnable("RunnableMethod"), 134 obj_(obj), 135 meth_(meth), 136 params_(std::forward<Params>(params)) { 137 this->RetainCallee(obj_); 138 } 139 ~RunnableMethod() { ReleaseCallee(); } 140 141 NS_IMETHOD Run() override { 142 if (obj_) DispatchTupleToMethod(obj_, meth_, params_); 143 return NS_OK; 144 } 145 146 virtual nsresult Cancel() override { 147 ReleaseCallee(); 148 return NS_OK; 149 } 150 151 private: 152 void ReleaseCallee() { 153 if (obj_) { 154 RunnableMethodTraits<T>::ReleaseCallee(obj_); 155 obj_ = nullptr; 156 } 157 } 158 159 // This is owning because of the RetainCallee and ReleaseCallee calls in the 160 // constructor and destructor. 161 T* MOZ_OWNING_REF obj_; 162 Method meth_; 163 Params params_; 164 }; 165 166 namespace dont_add_new_uses_of_this { 167 168 // Don't add new uses of this!!!! 169 template <class T, class Method, typename... Args> 170 inline already_AddRefed<mozilla::Runnable> NewRunnableMethod(T* object, 171 Method method, 172 Args&&... args) { 173 typedef std::tuple<std::decay_t<Args>...> ArgsTuple; 174 RefPtr<mozilla::Runnable> t = new RunnableMethod<T, Method, ArgsTuple>( 175 object, method, std::make_tuple(std::forward<Args>(args)...)); 176 return t.forget(); 177 } 178 179 } // namespace dont_add_new_uses_of_this 180 181 // RunnableFunction and NewRunnableFunction implementation --------------------- 182 183 template <class Function, class Params> 184 class RunnableFunction : public mozilla::CancelableRunnable { 185 public: 186 RunnableFunction(const char* name, Function function, Params&& params) 187 : mozilla::CancelableRunnable(name), 188 function_(function), 189 params_(std::forward<Params>(params)) {} 190 191 ~RunnableFunction() {} 192 193 NS_IMETHOD Run() override { 194 if (function_) DispatchTupleToFunction(function_, params_); 195 return NS_OK; 196 } 197 198 virtual nsresult Cancel() override { 199 function_ = nullptr; 200 return NS_OK; 201 } 202 203 Function function_; 204 Params params_; 205 }; 206 207 template <class Function, typename... Args> 208 inline already_AddRefed<mozilla::CancelableRunnable> 209 NewCancelableRunnableFunction(const char* name, Function function, 210 Args&&... args) { 211 typedef std::tuple<std::decay_t<Args>...> ArgsTuple; 212 RefPtr<mozilla::CancelableRunnable> t = 213 new RunnableFunction<Function, ArgsTuple>( 214 name, function, std::make_tuple(std::forward<Args>(args)...)); 215 return t.forget(); 216 } 217 218 template <class Function, typename... Args> 219 inline already_AddRefed<mozilla::Runnable> NewRunnableFunction( 220 const char* name, Function function, Args&&... args) { 221 typedef std::tuple<std::decay_t<Args>...> ArgsTuple; 222 RefPtr<mozilla::Runnable> t = new RunnableFunction<Function, ArgsTuple>( 223 name, function, std::make_tuple(std::forward<Args>(args)...)); 224 return t.forget(); 225 } 226 227 #endif // BASE_TASK_H_