From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- ipc/chromium/src/base/task.h | 356 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 ipc/chromium/src/base/task.h (limited to 'ipc/chromium/src/base/task.h') diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h new file mode 100644 index 0000000000..842fa8487f --- /dev/null +++ b/ipc/chromium/src/base/task.h @@ -0,0 +1,356 @@ +/* -*- 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 "nsISupportsImpl.h" +#include "nsThreadUtils.h" + +#include +#include + +// 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 +void CallMethod(std::index_sequence, ObjT* obj, Method method, + std::tuple& arg) { + (obj->*method)(std::move(std::get(arg))...); +} + +// Same as above, but call a function. +template +void CallFunction(std::index_sequence, Function function, + std::tuple& arg) { + (*function)(std::move(std::get(arg))...); +} + +} // namespace details + +// Call a method on the given object. Arguments are passed by move semantics +// from the given tuple. +template +void DispatchTupleToMethod(ObjT* obj, Method method, std::tuple& arg) { + details::CallMethod(std::index_sequence_for{}, obj, method, arg); +} + +// Same as above, but call a function. +template +void DispatchTupleToFunction(Function function, std::tuple& arg) { + details::CallFunction(std::index_sequence_for{}, 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 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 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 ScopedRunnableMethodFactory : public RevocableStore { + public: + explicit ScopedRunnableMethodFactory(T* object) : object_(object) {} + + template + inline already_AddRefed NewRunnableMethod( + Method method, Elements&&... elements) { + typedef std::tuple...> ArgsTuple; + typedef RunnableMethod Runnable; + typedef typename ScopedTaskFactory::TaskWrapper TaskWrapper; + + RefPtr task = new TaskWrapper(this); + task->Init(object_, method, + std::make_tuple(std::forward(elements)...)); + return task.forget(); + } + + protected: + template + class RunnableMethod : public mozilla::Runnable { + public: + RunnableMethod() + : mozilla::Runnable("ScopedRunnableMethodFactory::RunnableMethod") {} + + void Init(T* obj, Method meth, Params&& params) { + obj_ = obj; + meth_ = meth; + params_ = std::forward(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 DeleteTask : public mozilla::CancelableRunnable { + public: + explicit DeleteTask(T* obj) + : mozilla::CancelableRunnable("DeleteTask"), 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 +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 +struct RunnableMethodTraits { + static void RetainCallee(const T* obj) { const_cast(obj)->AddRef(); } + static void ReleaseCallee(const T* obj) { const_cast(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 RunnableMethod : public mozilla::CancelableRunnable, + public RunnableMethodTraits { + public: + RunnableMethod(T* obj, Method meth, Params&& params) + : mozilla::CancelableRunnable("RunnableMethod"), + obj_(obj), + meth_(meth), + params_(std::forward(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::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 +inline already_AddRefed NewRunnableMethod(T* object, + Method method, + Args&&... args) { + typedef std::tuple...> ArgsTuple; + RefPtr t = new RunnableMethod( + object, method, std::make_tuple(std::forward(args)...)); + return t.forget(); +} + +} // namespace dont_add_new_uses_of_this + +// RunnableFunction and NewRunnableFunction implementation --------------------- + +template +class RunnableFunction : public mozilla::CancelableRunnable { + public: + RunnableFunction(const char* name, Function function, Params&& params) + : mozilla::CancelableRunnable(name), + function_(function), + params_(std::forward(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 +inline already_AddRefed +NewCancelableRunnableFunction(const char* name, Function function, + Args&&... args) { + typedef std::tuple...> ArgsTuple; + RefPtr t = + new RunnableFunction( + name, function, std::make_tuple(std::forward(args)...)); + return t.forget(); +} + +template +inline already_AddRefed NewRunnableFunction( + const char* name, Function function, Args&&... args) { + typedef std::tuple...> ArgsTuple; + RefPtr t = new RunnableFunction( + name, function, std::make_tuple(std::forward(args)...)); + return t.forget(); +} + +#endif // BASE_TASK_H_ -- cgit v1.2.3