1 // Copyright 2020 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TASK_BIND_POST_TASK_INTERNAL_H_ 6 #define BASE_TASK_BIND_POST_TASK_INTERNAL_H_ 7 8 #include <utility> 9 10 #include "base/check.h" 11 #include "base/functional/bind.h" 12 #include "base/functional/callback.h" 13 #include "base/location.h" 14 #include "base/task/task_runner.h" 15 #include "base/task/thread_pool/thread_pool_instance.h" 16 17 namespace base { 18 namespace internal { 19 20 // Helper class to ensure that the input callback is always invoked and 21 // destroyed on the provided task runner. 22 template <typename CallbackType> 23 class BindPostTaskTrampoline { 24 public: BindPostTaskTrampoline(scoped_refptr<TaskRunner> task_runner,const Location & location,CallbackType callback)25 BindPostTaskTrampoline(scoped_refptr<TaskRunner> task_runner, 26 const Location& location, 27 CallbackType callback) 28 : task_runner_(std::move(task_runner)), 29 location_(location), 30 callback_(std::move(callback)) { 31 DCHECK(task_runner_); 32 // Crash immediately instead of when trying to Run() `callback_` on the 33 // destination `task_runner_`. 34 CHECK(callback_); 35 } 36 37 BindPostTaskTrampoline(const BindPostTaskTrampoline& other) = delete; 38 BindPostTaskTrampoline& operator=(const BindPostTaskTrampoline& other) = 39 delete; 40 ~BindPostTaskTrampoline()41 ~BindPostTaskTrampoline() { 42 if (callback_) { 43 // Allow this task to be leaked on shutdown even if `task_runner_` has the 44 // TaskShutdownBehaviour::BLOCK_SHUTDOWN trait. Without `fizzler`, such a 45 // task runner would DCHECK when posting to `task_runner_` after shutdown. 46 // Ignore this DCHECK as the poster isn't in control when its Callback is 47 // destroyed late into shutdown. Ref. crbug.com/1375270. 48 base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks fizzler; 49 50 // Post a task to ensure that `callback_` is destroyed on `task_runner_`. 51 // The callback's BindState may own an object that isn't threadsafe and is 52 // unsafe to destroy on a different task runner. 53 // 54 // Note that while this guarantees `callback_` will be destroyed when the 55 // posted task runs, it doesn't guarantee the ref-counted BindState is 56 // destroyed at the same time. If the callback was copied before being 57 // passed to BindPostTaskTrampoline then the BindState can outlive 58 // `callback_`, so the user must ensure any other copies of the callback 59 // are also destroyed on the correct task runner. 60 task_runner_->PostTask( 61 location_, 62 base::BindOnce(&DestroyCallbackOnTaskRunner, std::move(callback_))); 63 } 64 } 65 66 template <typename... Args> Run(Args...args)67 void Run(Args... args) { 68 // If CallbackType is a OnceCallback then GetClosure() consumes `callback_`. 69 task_runner_->PostTask(location_, 70 GetClosure(&callback_, std::forward<Args>(args)...)); 71 } 72 73 private: GetClosure(OnceClosure * callback)74 static OnceClosure GetClosure(OnceClosure* callback) { 75 // `callback` is already a closure, no need to call BindOnce(). 76 return std::move(*callback); 77 } 78 79 template <typename... Args> GetClosure(OnceCallback<void (Args...)> * callback,Args &&...args)80 static OnceClosure GetClosure(OnceCallback<void(Args...)>* callback, 81 Args&&... args) { 82 return base::BindOnce(std::move(*callback), std::forward<Args>(args)...); 83 } 84 GetClosure(RepeatingClosure * callback)85 static OnceClosure GetClosure(RepeatingClosure* callback) { 86 // `callback` is already a closure, no need to call BindOnce(). 87 return *callback; 88 } 89 90 template <typename... Args> GetClosure(RepeatingCallback<void (Args...)> * callback,Args &&...args)91 static OnceClosure GetClosure(RepeatingCallback<void(Args...)>* callback, 92 Args&&... args) { 93 return base::BindOnce(*callback, std::forward<Args>(args)...); 94 } 95 DestroyCallbackOnTaskRunner(CallbackType callback)96 static void DestroyCallbackOnTaskRunner(CallbackType callback) {} 97 98 const scoped_refptr<TaskRunner> task_runner_; 99 const Location location_; 100 CallbackType callback_; 101 }; 102 103 } // namespace internal 104 } // namespace base 105 106 #endif // BASE_TASK_BIND_POST_TASK_INTERNAL_H_ 107