1 // Copyright (c) 2011 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 #include "base/threading/post_task_and_reply_impl.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/threading/sequenced_task_runner_handle.h"
15
16 namespace base {
17
18 namespace {
19
20 class PostTaskAndReplyRelay {
21 public:
PostTaskAndReplyRelay(const Location & from_here,OnceClosure task,OnceClosure reply)22 PostTaskAndReplyRelay(const Location& from_here,
23 OnceClosure task,
24 OnceClosure reply)
25 : from_here_(from_here),
26 task_(std::move(task)),
27 reply_(std::move(reply)) {}
28 PostTaskAndReplyRelay(PostTaskAndReplyRelay&&) = default;
29
~PostTaskAndReplyRelay()30 ~PostTaskAndReplyRelay() {
31 if (reply_) {
32 // This can run:
33 // 1) On origin sequence, when:
34 // 1a) Posting |task_| fails.
35 // 1b) |reply_| is cancelled before running.
36 // 1c) The DeleteSoon() below is scheduled.
37 // 2) On destination sequence, when:
38 // 2a) |task_| is cancelled before running.
39 // 2b) Posting |reply_| fails.
40
41 if (!reply_task_runner_->RunsTasksInCurrentSequence()) {
42 // Case 2a) or 2b).
43 //
44 // Destroy callbacks asynchronously on |reply_task_runner| since their
45 // destructors can rightfully be affine to it. As always, DeleteSoon()
46 // might leak its argument if the target execution environment is
47 // shutdown (e.g. MessageLoop deleted, TaskScheduler shutdown).
48 //
49 // Note: while it's obvious why |reply_| can be affine to
50 // |reply_task_runner|, the reason that |task_| can also be affine to it
51 // is that it if neither tasks ran, |task_| may still hold an object
52 // which was intended to be moved to |reply_| when |task_| ran (such an
53 // object's destruction can be affine to |reply_task_runner_| -- e.g.
54 // https://crbug.com/829122).
55 auto relay_to_delete =
56 std::make_unique<PostTaskAndReplyRelay>(std::move(*this));
57 ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get());
58 reply_task_runner_->DeleteSoon(from_here_, std::move(relay_to_delete));
59 }
60
61 // Case 1a), 1b), 1c).
62 //
63 // Callbacks will be destroyed synchronously at the end of this scope.
64 } else {
65 // This can run when both callbacks have run or have been moved to another
66 // PostTaskAndReplyRelay instance. If |reply_| is null, |task_| must be
67 // null too.
68 DCHECK(!task_);
69 }
70 }
71
72 // No assignment operator because of const members.
73 PostTaskAndReplyRelay& operator=(PostTaskAndReplyRelay&&) = delete;
74
75 // Static function is used because it is not possible to bind a method call to
76 // a non-pointer type.
RunTaskAndPostReply(PostTaskAndReplyRelay relay)77 static void RunTaskAndPostReply(PostTaskAndReplyRelay relay) {
78 DCHECK(relay.task_);
79 std::move(relay.task_).Run();
80
81 // Keep a reference to the reply TaskRunner for the PostTask() call before
82 // |relay| is moved into a callback.
83 scoped_refptr<SequencedTaskRunner> reply_task_runner =
84 relay.reply_task_runner_;
85
86 reply_task_runner->PostTask(
87 relay.from_here_,
88 BindOnce(&PostTaskAndReplyRelay::RunReply, std::move(relay)));
89 }
90
91 private:
92 // Static function is used because it is not possible to bind a method call to
93 // a non-pointer type.
RunReply(PostTaskAndReplyRelay relay)94 static void RunReply(PostTaskAndReplyRelay relay) {
95 DCHECK(!relay.task_);
96 DCHECK(relay.reply_);
97 std::move(relay.reply_).Run();
98 }
99
100 const Location from_here_;
101 OnceClosure task_;
102 OnceClosure reply_;
103 const scoped_refptr<SequencedTaskRunner> reply_task_runner_ =
104 SequencedTaskRunnerHandle::Get();
105
106 DISALLOW_COPY_AND_ASSIGN(PostTaskAndReplyRelay);
107 };
108
109 } // namespace
110
111 namespace internal {
112
PostTaskAndReply(const Location & from_here,OnceClosure task,OnceClosure reply)113 bool PostTaskAndReplyImpl::PostTaskAndReply(const Location& from_here,
114 OnceClosure task,
115 OnceClosure reply) {
116 DCHECK(task) << from_here.ToString();
117 DCHECK(reply) << from_here.ToString();
118
119 return PostTask(from_here,
120 BindOnce(&PostTaskAndReplyRelay::RunTaskAndPostReply,
121 PostTaskAndReplyRelay(from_here, std::move(task),
122 std::move(reply))));
123 }
124
125 } // namespace internal
126
127 } // namespace base
128