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 requires std::is_void_v<ReturnType> 68 OnceCallback<void(Args...)> BindPostTask( 69 scoped_refptr<TaskRunner> task_runner, 70 OnceCallback<ReturnType(Args...)> callback, 71 const Location& location = FROM_HERE) { 72 using Helper = internal::BindPostTaskTrampoline<OnceCallback<void(Args...)>>; 73 74 return base::BindOnce( 75 &Helper::template Run<Args...>, 76 std::make_unique<Helper>(std::move(task_runner), location, 77 std::move(callback))); 78 } 79 80 // Creates a RepeatingCallback that will run |callback| on |task_runner|. When 81 // the returned callback is destroyed a task will be posted to destroy the input 82 // |callback| on |task_runner|. 83 template <typename ReturnType, typename... Args> 84 requires std::is_void_v<ReturnType> 85 RepeatingCallback<void(Args...)> BindPostTask( 86 scoped_refptr<TaskRunner> task_runner, 87 RepeatingCallback<ReturnType(Args...)> callback, 88 const Location& location = FROM_HERE) { 89 using Helper = 90 internal::BindPostTaskTrampoline<RepeatingCallback<void(Args...)>>; 91 92 return base::BindRepeating( 93 &Helper::template Run<Args...>, 94 std::make_unique<Helper>(std::move(task_runner), location, 95 std::move(callback))); 96 } 97 98 // Creates a OnceCallback or RepeatingCallback that will run the `callback` on 99 // the default SequencedTaskRunner for the current sequence, i.e. 100 // `SequencedTaskRunner::GetCurrentDefault()`. 101 // Notes: 102 // - Please prefer using `base::SequenceBound<T>` if applicable. 103 // - Please consider using `base::PostTaskAndReplyWithResult()` instead where 104 // appropriate. 105 // - Please consider using an explicit task runner. 106 // - Only use this helper as a last resort if none of the above apply. 107 108 template <typename ReturnType, typename... Args> 109 requires std::is_void_v<ReturnType> 110 OnceCallback<void(Args...)> BindPostTaskToCurrentDefault( 111 OnceCallback<ReturnType(Args...)> callback, 112 const Location& location = FROM_HERE) { 113 return BindPostTask(SequencedTaskRunner::GetCurrentDefault(), 114 std::move(callback), location); 115 } 116 117 template <typename ReturnType, typename... Args> 118 requires std::is_void_v<ReturnType> 119 RepeatingCallback<void(Args...)> BindPostTaskToCurrentDefault( 120 RepeatingCallback<ReturnType(Args...)> callback, 121 const Location& location = FROM_HERE) { 122 return BindPostTask(SequencedTaskRunner::GetCurrentDefault(), 123 std::move(callback), location); 124 } 125 126 } // namespace base 127 128 #endif // BASE_TASK_BIND_POST_TASK_H_ 129