xref: /aosp_15_r20/external/cronet/base/task/bind_post_task_internal.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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