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 "base/bind.h" 8 #include "base/location.h" 9 #include "base/single_thread_task_runner.h" 10 #include "base/thread_task_runner_handle.h" 11 12 namespace base { 13 14 namespace { 15 16 // This relay class remembers the MessageLoop that it was created on, and 17 // ensures that both the |task| and |reply| Closures are deleted on this same 18 // thread. Also, |task| is guaranteed to be deleted before |reply| is run or 19 // deleted. 20 // 21 // If this is not possible because the originating MessageLoop is no longer 22 // available, the the |task| and |reply| Closures are leaked. Leaking is 23 // considered preferable to having a thread-safetey violations caused by 24 // invoking the Closure destructor on the wrong thread. 25 class PostTaskAndReplyRelay { 26 public: 27 PostTaskAndReplyRelay(const tracked_objects::Location& from_here, 28 const Closure& task, const Closure& reply) 29 : from_here_(from_here), 30 origin_loop_(ThreadTaskRunnerHandle::Get()) { 31 task_ = task; 32 reply_ = reply; 33 } 34 35 ~PostTaskAndReplyRelay() { 36 DCHECK(origin_loop_->BelongsToCurrentThread()); 37 task_.Reset(); 38 reply_.Reset(); 39 } 40 41 void Run() { 42 task_.Run(); 43 origin_loop_->PostTask( 44 from_here_, 45 Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct, 46 base::Unretained(this))); 47 } 48 49 private: 50 void RunReplyAndSelfDestruct() { 51 DCHECK(origin_loop_->BelongsToCurrentThread()); 52 53 // Force |task_| to be released before |reply_| is to ensure that no one 54 // accidentally depends on |task_| keeping one of its arguments alive while 55 // |reply_| is executing. 56 task_.Reset(); 57 58 reply_.Run(); 59 60 // Cue mission impossible theme. 61 delete this; 62 } 63 64 tracked_objects::Location from_here_; 65 scoped_refptr<SingleThreadTaskRunner> origin_loop_; 66 Closure reply_; 67 Closure task_; 68 }; 69 70 } // namespace 71 72 namespace internal { 73 74 bool PostTaskAndReplyImpl::PostTaskAndReply( 75 const tracked_objects::Location& from_here, 76 const Closure& task, 77 const Closure& reply) { 78 PostTaskAndReplyRelay* relay = 79 new PostTaskAndReplyRelay(from_here, task, reply); 80 if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run, 81 Unretained(relay)))) { 82 delete relay; 83 return false; 84 } 85 86 return true; 87 } 88 89 } // namespace internal 90 91 } // namespace base 92