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/sequence_checker.h" 14 #include "base/sequenced_task_runner.h" 15 #include "base/threading/sequenced_task_runner_handle.h" 16 17 namespace base { 18 19 namespace { 20 21 // This relay class remembers the sequence that it was created on, and ensures 22 // that both the |task| and |reply| Closures are deleted on this same sequence. 23 // Also, |task| is guaranteed to be deleted before |reply| is run or deleted. 24 // 25 // If RunReplyAndSelfDestruct() doesn't run because the originating execution 26 // context is no longer available, then the |task| and |reply| Closures are 27 // leaked. Leaking is considered preferable to having a thread-safetey 28 // violations caused by invoking the Closure destructor on the wrong sequence. 29 class PostTaskAndReplyRelay { 30 public: 31 PostTaskAndReplyRelay(const tracked_objects::Location& from_here, 32 OnceClosure task, 33 OnceClosure reply) 34 : sequence_checker_(), 35 from_here_(from_here), 36 origin_task_runner_(SequencedTaskRunnerHandle::Get()), 37 reply_(std::move(reply)), 38 task_(std::move(task)) {} 39 40 ~PostTaskAndReplyRelay() { 41 DCHECK(sequence_checker_.CalledOnValidSequence()); 42 } 43 44 void RunTaskAndPostReply() { 45 std::move(task_).Run(); 46 origin_task_runner_->PostTask( 47 from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct, 48 base::Unretained(this))); 49 } 50 51 private: 52 void RunReplyAndSelfDestruct() { 53 DCHECK(sequence_checker_.CalledOnValidSequence()); 54 55 // Ensure |task_| has already been released before |reply_| to ensure that 56 // no one accidentally depends on |task_| keeping one of its arguments alive 57 // while |reply_| is executing. 58 DCHECK(!task_); 59 60 std::move(reply_).Run(); 61 62 // Cue mission impossible theme. 63 delete this; 64 } 65 66 const SequenceChecker sequence_checker_; 67 const tracked_objects::Location from_here_; 68 const scoped_refptr<SequencedTaskRunner> origin_task_runner_; 69 OnceClosure reply_; 70 OnceClosure task_; 71 }; 72 73 } // namespace 74 75 namespace internal { 76 77 bool PostTaskAndReplyImpl::PostTaskAndReply( 78 const tracked_objects::Location& from_here, 79 OnceClosure task, 80 OnceClosure reply) { 81 DCHECK(!task.is_null()) << from_here.ToString(); 82 DCHECK(!reply.is_null()) << from_here.ToString(); 83 PostTaskAndReplyRelay* relay = 84 new PostTaskAndReplyRelay(from_here, std::move(task), std::move(reply)); 85 // PostTaskAndReplyRelay self-destructs after executing |reply|. On the flip 86 // side though, it is intentionally leaked if the |task| doesn't complete 87 // before the origin sequence stops executing tasks. Annotate |relay| as leaky 88 // to avoid having to suppress every callsite which happens to flakily trigger 89 // this race. 90 ANNOTATE_LEAKING_OBJECT_PTR(relay); 91 if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::RunTaskAndPostReply, 92 Unretained(relay)))) { 93 delete relay; 94 return false; 95 } 96 97 return true; 98 } 99 100 } // namespace internal 101 102 } // namespace base 103