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