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: 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 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. 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. 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 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