// Copyright 2020 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_BIND_POST_TASK_INTERNAL_H_ #define BASE_TASK_BIND_POST_TASK_INTERNAL_H_ #include #include "base/bind.h" #include "base/callback.h" #include "base/check.h" #include "base/location.h" #include "base/task/task_runner.h" namespace base { namespace internal { // Helper class to ensure that the input callback is always invoked and // destroyed on the provided task runner. template class BindPostTaskTrampoline { public: BindPostTaskTrampoline(scoped_refptr task_runner, const Location& location, CallbackType callback) : task_runner_(std::move(task_runner)), location_(location), callback_(std::move(callback)) { DCHECK(task_runner_); // Crash immediately instead of when trying to Run() `callback_` on the // destination `task_runner_`. CHECK(callback_); } BindPostTaskTrampoline(const BindPostTaskTrampoline& other) = delete; BindPostTaskTrampoline& operator=(const BindPostTaskTrampoline& other) = delete; ~BindPostTaskTrampoline() { if (callback_) { // Post a task to ensure that `callback_` is destroyed on `task_runner_`. // The callback's BindState may own an object that isn't threadsafe and is // unsafe to destroy on a different task runner. // // Note that while this guarantees `callback_` will be destroyed when the // posted task runs, it doesn't guarantee the ref-counted BindState is // destroyed at the same time. If the callback was copied before being // passed to BindPostTaskTrampoline then the BindState can outlive // `callback_`, so the user must ensure any other copies of the callback // are also destroyed on the correct task runner. task_runner_->PostTask(location_, BindOnce(&DestroyCallbackOnTaskRunner, std::move(callback_))); } } template void Run(Args... args) { // If CallbackType is a OnceCallback then GetClosure() consumes `callback_`. task_runner_->PostTask(location_, GetClosure(&callback_, std::forward(args)...)); } private: static OnceClosure GetClosure(OnceClosure* callback) { // `callback` is already a closure, no need to call BindOnce(). return std::move(*callback); } template static OnceClosure GetClosure(OnceCallback* callback, Args&&... args) { return BindOnce(std::move(*callback), std::forward(args)...); } static OnceClosure GetClosure(RepeatingClosure* callback) { // `callback` is already a closure, no need to call BindOnce(). return *callback; } template static OnceClosure GetClosure(RepeatingCallback* callback, Args&&... args) { return BindOnce(*callback, std::forward(args)...); } static void DestroyCallbackOnTaskRunner(CallbackType callback) {} const scoped_refptr task_runner_; const Location location_; CallbackType callback_; }; } // namespace internal } // namespace base #endif // BASE_TASK_BIND_POST_TASK_INTERNAL_H_