• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_H_
6 #define BASE_TASK_BIND_POST_TASK_H_
7 
8 #include <memory>
9 #include <type_traits>
10 #include <utility>
11 
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/location.h"
15 #include "base/task/bind_post_task_internal.h"
16 #include "base/task/sequenced_task_runner.h"
17 #include "base/task/task_runner.h"
18 
19 // BindPostTask() is a helper function for binding a OnceCallback or
20 // RepeatingCallback to a task runner. BindPostTask(task_runner, callback)
21 // returns a task runner bound callback with an identical type to |callback|.
22 // The returned callback will take the same arguments as the input |callback|.
23 // Invoking Run() on the returned callback will post a task to run |callback| on
24 // target |task_runner| with the provided arguments.
25 //
26 // This is typically used when a callback must be invoked on a specific task
27 // runner but is provided as a result callback to a function that runs
28 // asynchronously on a different task runner.
29 //
30 // Example:
31 //    // |result_cb| can only be safely run on |my_task_runner|.
32 //    auto result_cb = BindOnce(&Foo::ReceiveReply, foo);
33 //    // Note that even if |returned_cb| is never run |result_cb| will attempt
34 //    // to be destroyed on |my_task_runner|.
35 //    auto returned_cb = BindPostTask(my_task_runner, std::move(result_cb));
36 //    // RunAsyncTask() will run the provided callback upon completion.
37 //    other_task_runner->PostTask(FROM_HERE,
38 //                                BindOnce(&RunAsyncTask,
39 //                                         std::move(returned_cb)));
40 //
41 // If the example provided |result_cb| to RunAsyncTask() then |result_cb| would
42 // run unsafely on |other_task_runner|. Instead RunAsyncTask() will run
43 // |returned_cb| which will post a task to |current_task_runner| before running
44 // |result_cb| safely.
45 //
46 // An alternative approach in the example above is to change RunAsyncTask() to
47 // also take a task runner as an argument and have RunAsyncTask() post the task.
48 // For cases where that isn't desirable BindPostTask() provides a convenient
49 // alternative.
50 //
51 // The input |callback| will always attempt to be destroyed on the target task
52 // runner. Even if the returned callback is never invoked, a task will be posted
53 // to destroy the input |callback|. However, if the target task runner has
54 // shutdown this is no longer possible. PostTask() will return false and the
55 // callback will be destroyed immediately on the current thread.
56 //
57 // The input |callback| must have a void return type to be compatible with
58 // PostTask(). If you want to drop the callback return value then use
59 // base::IgnoreResult(&Func) when creating the input |callback|.
60 
61 namespace base {
62 
63 // Creates a OnceCallback that will run |callback| on |task_runner|. If the
64 // returned callback is destroyed without being run then |callback| will be
65 // be destroyed on |task_runner|.
66 template <typename ReturnType, typename... Args>
67 OnceCallback<void(Args...)> BindPostTask(
68     scoped_refptr<TaskRunner> task_runner,
69     OnceCallback<ReturnType(Args...)> callback,
70     const Location& location = FROM_HERE) {
71   static_assert(std::is_same<ReturnType, void>::value,
72                 "OnceCallback must have void return type in order to produce a "
73                 "closure for PostTask(). Use base::IgnoreResult() to drop the "
74                 "return value if desired.");
75 
76   using Helper = internal::BindPostTaskTrampoline<OnceCallback<void(Args...)>>;
77 
78   return base::BindOnce(
79       &Helper::template Run<Args...>,
80       std::make_unique<Helper>(std::move(task_runner), location,
81                                std::move(callback)));
82 }
83 
84 // Creates a RepeatingCallback that will run |callback| on |task_runner|. When
85 // the returned callback is destroyed a task will be posted to destroy the input
86 // |callback| on |task_runner|.
87 template <typename ReturnType, typename... Args>
88 RepeatingCallback<void(Args...)> BindPostTask(
89     scoped_refptr<TaskRunner> task_runner,
90     RepeatingCallback<ReturnType(Args...)> callback,
91     const Location& location = FROM_HERE) {
92   static_assert(std::is_same<ReturnType, void>::value,
93                 "RepeatingCallback must have void return type in order to "
94                 "produce a closure for PostTask(). Use base::IgnoreResult() to "
95                 "drop the return value if desired.");
96 
97   using Helper =
98       internal::BindPostTaskTrampoline<RepeatingCallback<void(Args...)>>;
99 
100   return base::BindRepeating(
101       &Helper::template Run<Args...>,
102       std::make_unique<Helper>(std::move(task_runner), location,
103                                std::move(callback)));
104 }
105 
106 // Creates a OnceCallback or RepeatingCallback that will run the `callback` on
107 // the default SequencedTaskRunner for the current sequence, i.e.
108 // `SequencedTaskRunner::GetCurrentDefault()`.
109 // Notes:
110 // - Please prefer using `base::SequenceBound<T>` if applicable.
111 // - Please consider using `base::PostTaskAndReplyWithResult()` instead where
112 // appropriate.
113 // - Please consider using an explicit task runner.
114 // - Only use this helper as a last resort if none of the above apply.
115 
116 template <typename ReturnType, typename... Args>
117 OnceCallback<void(Args...)> BindPostTaskToCurrentDefault(
118     OnceCallback<ReturnType(Args...)> callback,
119     const Location& location = FROM_HERE) {
120   return BindPostTask(SequencedTaskRunner::GetCurrentDefault(),
121                       std::move(callback), location);
122 }
123 
124 template <typename ReturnType, typename... Args>
125 RepeatingCallback<void(Args...)> BindPostTaskToCurrentDefault(
126     RepeatingCallback<ReturnType(Args...)> callback,
127     const Location& location = FROM_HERE) {
128   return BindPostTask(SequencedTaskRunner::GetCurrentDefault(),
129                       std::move(callback), location);
130 }
131 
132 }  // namespace base
133 
134 #endif  // BASE_TASK_BIND_POST_TASK_H_
135