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