diff options
Diffstat (limited to 'ipc/chromium/src/base/task.h')
-rw-r--r-- | ipc/chromium/src/base/task.h | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h new file mode 100644 index 000000000..10dc9c488 --- /dev/null +++ b/ipc/chromium/src/base/task.h @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_TASK_H_ +#define BASE_TASK_H_ + +#include "base/revocable_store.h" +#include "base/tuple.h" +#include "mozilla/IndexSequence.h" +#include "mozilla/Tuple.h" +#include "nsISupportsImpl.h" +#include "nsThreadUtils.h" + +// Helper functions so that we can call a function a pass it arguments that come +// from a Tuple. + +namespace details { + +// Call the given method on the given object. Arguments are passed by move +// semantics from the given tuple. If the tuple has length N, the sequence must +// be IndexSequence<0, 1, ..., N-1>. +template<size_t... Indices, class ObjT, class Method, typename... Args> +void CallMethod(mozilla::IndexSequence<Indices...>, ObjT* obj, Method method, + mozilla::Tuple<Args...>& arg) +{ + (obj->*method)(mozilla::Move(mozilla::Get<Indices>(arg))...); +} + +// Same as above, but call a function. +template<size_t... Indices, typename Function, typename... Args> +void CallFunction(mozilla::IndexSequence<Indices...>, Function function, + mozilla::Tuple<Args...>& arg) +{ + (*function)(mozilla::Move(mozilla::Get<Indices>(arg))...); +} + +} // namespace details + +// Call a method on the given object. Arguments are passed by move semantics +// from the given tuple. +template<class ObjT, class Method, typename... Args> +void DispatchTupleToMethod(ObjT* obj, Method method, mozilla::Tuple<Args...>& arg) +{ + details::CallMethod(typename mozilla::IndexSequenceFor<Args...>::Type(), + obj, method, arg); +} + +// Same as above, but call a function. +template<typename Function, typename... Args> +void DispatchTupleToFunction(Function function, mozilla::Tuple<Args...>& arg) +{ + details::CallFunction(typename mozilla::IndexSequenceFor<Args...>::Type(), + function, arg); +} + +// Scoped Factories ------------------------------------------------------------ +// +// These scoped factory objects can be used by non-refcounted objects to safely +// place tasks in a message loop. Each factory guarantees that the tasks it +// produces will not run after the factory is destroyed. Commonly, factories +// are declared as class members, so the class' tasks will automatically cancel +// when the class instance is destroyed. +// +// Exampe Usage: +// +// class MyClass { +// private: +// // This factory will be used to schedule invocations of SomeMethod. +// ScopedRunnableMethodFactory<MyClass> some_method_factory_; +// +// public: +// // It is safe to suppress warning 4355 here. +// MyClass() : some_method_factory_(this) { } +// +// void SomeMethod() { +// // If this function might be called directly, you might want to revoke +// // any outstanding runnable methods scheduled to call it. If it's not +// // referenced other than by the factory, this is unnecessary. +// some_method_factory_.RevokeAll(); +// ... +// } +// +// void ScheduleSomeMethod() { +// // If you'd like to only only have one pending task at a time, test for +// // |empty| before manufacturing another task. +// if (!some_method_factory_.empty()) +// return; +// +// // The factories are not thread safe, so always invoke on +// // |MessageLoop::current()|. +// MessageLoop::current()->PostDelayedTask( +// some_method_factory_.NewRunnableMethod(&MyClass::SomeMethod), +// kSomeMethodDelayMS); +// } +// }; + +// A ScopedTaskFactory produces tasks of type |TaskType| and prevents them from +// running after it is destroyed. +template<class TaskType> +class ScopedTaskFactory : public RevocableStore { + public: + ScopedTaskFactory() { } + + // Create a new task. + inline TaskType* NewTask() { + return new TaskWrapper(this); + } + + class TaskWrapper : public TaskType { + public: + explicit TaskWrapper(RevocableStore* store) : revocable_(store) { } + + NS_IMETHOD Run() override { + if (!revocable_.revoked()) + TaskType::Run(); + return NS_OK; + } + + ~TaskWrapper() { + NS_ASSERT_OWNINGTHREAD(TaskWrapper); + } + + private: + Revocable revocable_; + + NS_DECL_OWNINGTHREAD + + DISALLOW_EVIL_CONSTRUCTORS(TaskWrapper); + }; + + private: + DISALLOW_EVIL_CONSTRUCTORS(ScopedTaskFactory); +}; + +// A ScopedRunnableMethodFactory creates runnable methods for a specified +// object. This is particularly useful for generating callbacks for +// non-reference counted objects when the factory is a member of the object. +template<class T> +class ScopedRunnableMethodFactory : public RevocableStore { + public: + explicit ScopedRunnableMethodFactory(T* object) : object_(object) { } + + template <class Method, typename... Elements> + inline already_AddRefed<mozilla::Runnable> + NewRunnableMethod(Method method, Elements&&... elements) { + typedef mozilla::Tuple<typename mozilla::Decay<Elements>::Type...> ArgsTuple; + typedef RunnableMethod<Method, ArgsTuple> Runnable; + typedef typename ScopedTaskFactory<Runnable>::TaskWrapper TaskWrapper; + + RefPtr<TaskWrapper> task = new TaskWrapper(this); + task->Init(object_, method, mozilla::MakeTuple(mozilla::Forward<Elements>(elements)...)); + return task.forget(); + } + + protected: + template <class Method, class Params> + class RunnableMethod : public mozilla::Runnable { + public: + RunnableMethod() { } + + void Init(T* obj, Method meth, Params&& params) { + obj_ = obj; + meth_ = meth; + params_ = mozilla::Forward<Params>(params); + } + + NS_IMETHOD Run() override { + DispatchTupleToMethod(obj_, meth_, params_); + return NS_OK; + } + + private: + T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by " + "external factors.") obj_; + Method meth_; + Params params_; + + DISALLOW_EVIL_CONSTRUCTORS(RunnableMethod); + }; + + private: + T* object_; + + DISALLOW_EVIL_CONSTRUCTORS(ScopedRunnableMethodFactory); +}; + +// General task implementations ------------------------------------------------ + +// Task to delete an object +template<class T> +class DeleteTask : public mozilla::CancelableRunnable { + public: + explicit DeleteTask(T* obj) : obj_(obj) { + } + NS_IMETHOD Run() override { + delete obj_; + return NS_OK; + } + virtual nsresult Cancel() override { + obj_ = NULL; + return NS_OK; + } + private: + T* MOZ_UNSAFE_REF("The validity of this pointer must be enforced by " + "external factors.") obj_; +}; + +// RunnableMethodTraits -------------------------------------------------------- +// +// This traits-class is used by RunnableMethod to manage the lifetime of the +// callee object. By default, it is assumed that the callee supports AddRef +// and Release methods. A particular class can specialize this template to +// define other lifetime management. For example, if the callee is known to +// live longer than the RunnableMethod object, then a RunnableMethodTraits +// struct could be defined with empty RetainCallee and ReleaseCallee methods. + +template <class T> +struct RunnableMethodTraits { + static void RetainCallee(T* obj) { + obj->AddRef(); + } + static void ReleaseCallee(T* obj) { + obj->Release(); + } +}; + +// This allows using the NewRunnableMethod() functions with a const pointer +// to the callee object. See the similar support in nsRefPtr for a rationale +// of why this is reasonable. +template <class T> +struct RunnableMethodTraits<const T> { + static void RetainCallee(const T* obj) { + const_cast<T*>(obj)->AddRef(); + } + static void ReleaseCallee(const T* obj) { + const_cast<T*>(obj)->Release(); + } +}; + +// RunnableMethod and RunnableFunction ----------------------------------------- +// +// Runnable methods are a type of task that call a function on an object when +// they are run. We implement both an object and a set of NewRunnableMethod and +// NewRunnableFunction functions for convenience. These functions are +// overloaded and will infer the template types, simplifying calling code. +// +// The template definitions all use the following names: +// T - the class type of the object you're supplying +// this is not needed for the Static version of the call +// Method/Function - the signature of a pointer to the method or function you +// want to call +// Param - the parameter(s) to the method, possibly packed as a Tuple +// A - the first parameter (if any) to the method +// B - the second parameter (if any) to the mathod +// +// Put these all together and you get an object that can call a method whose +// signature is: +// R T::MyFunction([A[, B]]) +// +// Usage: +// PostTask(NewRunnableMethod(object, &Object::method[, a[, b]]) +// PostTask(NewRunnableFunction(&function[, a[, b]]) + +// RunnableMethod and NewRunnableMethod implementation ------------------------- + +template <class T, class Method, class Params> +class RunnableMethod : public mozilla::CancelableRunnable, + public RunnableMethodTraits<T> { + public: + RunnableMethod(T* obj, Method meth, Params&& params) + : obj_(obj), meth_(meth), params_(mozilla::Forward<Params>(params)) { + this->RetainCallee(obj_); + } + ~RunnableMethod() { + ReleaseCallee(); + } + + NS_IMETHOD Run() override { + if (obj_) + DispatchTupleToMethod(obj_, meth_, params_); + return NS_OK; + } + + virtual nsresult Cancel() override { + ReleaseCallee(); + return NS_OK; + } + + private: + void ReleaseCallee() { + if (obj_) { + RunnableMethodTraits<T>::ReleaseCallee(obj_); + obj_ = nullptr; + } + } + + // This is owning because of the RetainCallee and ReleaseCallee calls in the + // constructor and destructor. + T* MOZ_OWNING_REF obj_; + Method meth_; + Params params_; +}; + +namespace dont_add_new_uses_of_this { + +// Don't add new uses of this!!!! +template <class T, class Method, typename... Args> +inline already_AddRefed<mozilla::Runnable> +NewRunnableMethod(T* object, Method method, Args&&... args) { + typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple; + RefPtr<mozilla::Runnable> t = + new RunnableMethod<T, Method, ArgsTuple>(object, method, + mozilla::MakeTuple(mozilla::Forward<Args>(args)...)); + return t.forget(); +} + +} // namespace dont_add_new_uses_of_this + +// RunnableFunction and NewRunnableFunction implementation --------------------- + +template <class Function, class Params> +class RunnableFunction : public mozilla::CancelableRunnable { + public: + RunnableFunction(Function function, Params&& params) + : function_(function), params_(mozilla::Forward<Params>(params)) { + } + + ~RunnableFunction() { + } + + NS_IMETHOD Run() override { + if (function_) + DispatchTupleToFunction(function_, params_); + return NS_OK; + } + + virtual nsresult Cancel() override { + function_ = nullptr; + return NS_OK; + } + + Function function_; + Params params_; +}; + +template <class Function, typename... Args> +inline already_AddRefed<mozilla::CancelableRunnable> +NewCancelableRunnableFunction(Function function, Args&&... args) { + typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple; + RefPtr<mozilla::CancelableRunnable> t = + new RunnableFunction<Function, ArgsTuple>(function, + mozilla::MakeTuple(mozilla::Forward<Args>(args)...)); + return t.forget(); +} + +template <class Function, typename... Args> +inline already_AddRefed<mozilla::Runnable> +NewRunnableFunction(Function function, Args&&... args) { + typedef mozilla::Tuple<typename mozilla::Decay<Args>::Type...> ArgsTuple; + RefPtr<mozilla::Runnable> t = + new RunnableFunction<Function, ArgsTuple>(function, + mozilla::MakeTuple(mozilla::Forward<Args>(args)...)); + return t.forget(); +} + +#endif // BASE_TASK_H_ |