blob: 18bd9970fc04ed7f63f1df8fb0ffa63f7d4b707c [file] [log] [blame]
kylechardde7d232020-11-16 17:35:091// Copyright 2020 The Chromium Authors. All rights reserved.
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_BIND_POST_TASK_H_
6#define BASE_BIND_POST_TASK_H_
7
8#include <memory>
9#include <type_traits>
10
11#include "base/bind.h"
12#include "base/bind_post_task_internal.h"
13#include "base/callback.h"
14#include "base/location.h"
15#include "base/memory/ref_counted.h"
16#include "base/task_runner.h"
17
kylechar4ac8b3c2021-02-16 18:39:3418// BindPostTask() is a helper function for binding a OnceCallback or
19// RepeatingCallback to a task runner. BindPostTask(task_runner, callback)
20// returns a task runner bound callback with an identical type to |callback|.
21// The returned callback will take the same arguments as the input |callback|.
22// Invoking Run() on the returned callback will post a task to run |callback| on
23// target |task_runner| with the provided arguments.
kylechardde7d232020-11-16 17:35:0924//
25// This is typically used when a callback must be invoked on a specific task
26// runner but is provided as a result callback to a function that runs
27// asynchronously on a different task runner.
28//
29// Example:
30// // |result_cb| can only be safely run on |my_task_runner|.
31// auto result_cb = BindOnce(&Foo::ReceiveReply, foo);
32// // Note that even if |returned_cb| is never run |result_cb| will attempt
33// // to be destroyed on |my_task_runner|.
34// auto returned_cb = BindPostTask(my_task_runner, std::move(result_cb));
35// // RunAsyncTask() will run the provided callback upon completion.
36// other_task_runner->PostTask(FROM_HERE,
37// BindOnce(&RunAsyncTask,
38// std::move(returned_cb)));
39//
40// If the example provided |result_cb| to RunAsyncTask() then |result_cb| would
41// run unsafely on |other_task_runner|. Instead RunAsyncTask() will run
42// |returned_cb| which will post a task to |current_task_runner| before running
43// |result_cb| safely.
44//
45// An alternative approach in the example above is to change RunAsyncTask() to
46// also take a task runner as an argument and have RunAsyncTask() post the task.
47// For cases where that isn't desirable BindPostTask() provides a convenient
48// alternative.
49//
50// The input |callback| will always attempt to be destroyed on the target task
51// runner. Even if the returned callback is never invoked, a task will be posted
52// to destroy the input |callback|. However, if the target task runner has
53// shutdown this is no longer possible. PostTask() will return false and the
54// callback will be destroyed immediately on the current thread.
55//
56// The input |callback| must have a void return type to be compatible with
57// PostTask(). If you want to drop the callback return value then use
58// base::IgnoreResult(&Func) when creating the input |callback|.
59
60namespace base {
61
62// Creates a OnceCallback that will run |callback| on |task_runner|. If the
63// returned callback is destroyed without being run then |callback| will be
64// be destroyed on |task_runner|.
65template <typename ReturnType, typename... Args>
66OnceCallback<void(Args...)> BindPostTask(
67 scoped_refptr<TaskRunner> task_runner,
68 OnceCallback<ReturnType(Args...)> callback,
69 const Location& location = FROM_HERE) {
70 static_assert(std::is_same<ReturnType, void>::value,
71 "OnceCallback must have void return type in order to produce a "
72 "closure for PostTask(). Use base::IgnoreResult() to drop the "
73 "return value if desired.");
74
75 using Helper = internal::BindPostTaskTrampoline<OnceCallback<void(Args...)>>;
76
77 return base::BindOnce(
78 &Helper::template Run<Args...>,
79 std::make_unique<Helper>(std::move(task_runner), location,
80 std::move(callback)));
81}
82
kylechar4ac8b3c2021-02-16 18:39:3483// Creates a RepeatingCallback that will run |callback| on |task_runner|. When
84// the returned callback is destroyed a task will be posted to destroy the input
85// |callback| on |task_runner|.
86template <typename ReturnType, typename... Args>
87RepeatingCallback<void(Args...)> BindPostTask(
88 scoped_refptr<TaskRunner> task_runner,
89 RepeatingCallback<ReturnType(Args...)> callback,
90 const Location& location = FROM_HERE) {
91 static_assert(std::is_same<ReturnType, void>::value,
92 "RepeatingCallback must have void return type in order to "
93 "produce a closure for PostTask(). Use base::IgnoreResult() to "
94 "drop the return value if desired.");
95
96 using Helper =
97 internal::BindPostTaskTrampoline<RepeatingCallback<void(Args...)>>;
98
99 return base::BindRepeating(
100 &Helper::template Run<Args...>,
101 std::make_unique<Helper>(std::move(task_runner), location,
102 std::move(callback)));
103}
104
kylechardde7d232020-11-16 17:35:09105} // namespace base
106
107#endif // BASE_BIND_POST_TASK_H_